LeetCode 287. Find the Duplicate Number (python 判断环,时间复杂度O(n))
LeetCode 287. Find the Duplicate Number
暴力解法
时间 O(nlog(n)),空间O(n),按题目中Note“只用O(1)的空间”,照理是过不了的,但是可能判题并没有卡空间复杂度,所以也能AC。
class Solution:
# 基本思路为,将第一次出现的数字
def findDuplicate(self, nums: List[int]) -> int:
s = set()
for i in nums:
a = i in s
if a == True:
return i
else:
s.add(i)
双指针判断环
时间O(n),空间O(1),思路十分巧妙,但是使用条件比较苛刻。根据题目给出的条件,恰好能用这种解法,这应该也是出题人推荐的解法。
题意分析:
- 输入的序列有n+1个数字,每个数字在1~n之间取,这为构成数字环创造了条件。
- 只有一个数字有重复,所以只可能构成一个环。
注:上面所说的环是指1->2->3->1
以样例1为例:[1,3,4,2,2]
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 1 | 3 | 4 | 2 | 2 |
如下图所示,其中2->4->2构成环,入环点为2

解题思路
由题意分析可知,每个样例都可以画成这样一张图,我们只需要找出图中的环,并找出入环点,即为所求的重复数字key,下面都用key表示所求的重复数字。
为什么必定存在环
以样例1为例,图中出现了5个点0-4,图中存在5根指针线,5个点5根线,必定存在环。
n个点,点的范围去0~n-1,n根线,必定存在环。(n-1根线是恰好无环的情况,自己画图可知)
找环的方法
设置一个慢指针slow,一个快指针fast。slow每次走一步,fast每次走两步,如果slow与fast能相遇,说明图中存在环,并且相遇点一定存在于环中。
为什么key一定为入环点?
有题意分析中的表可知,key的入度一定大于1,即不止一个点可以直接到key。而key一定存在于环中,所以key一定为入环点。样例1中3,4都可到达2,2的入度2,2为入环点,即为所求的key。
怎么找入环点key?
slow和fast相交的点记为相遇点P。
slow和fast从起点0到相遇点P运行步骤如下:

这个相遇点P与起点0到达入环点key的步数 差距为环L的整数倍,故设置slow2从起点0开始,每次走一步,slow从相遇点P开始,每次走一步,slow和slow2一定会相遇在入环点key。
我们可以有一个小小的证明,如下图

设起点0到达入环点key的步数为x,相遇点P到达入环点key的步数为y。
设slow指针走到相遇点P的步数为t,fast走到相遇点P的步数为2*t。
设走完环一圈的步数为L
2 * t - x + y = M * L(一)
t - x + y = N * L (二)
fast指针在环中走的步数2t-x,此时到达相遇点P,key->P->key步数为2t-x+y = M * L,正好为L的M倍,M为常数。(一)式
slow指针在环中走的步数t-x,此时到达相遇点P,key->P->key步数为t-x+y = N * L,正好为L的N倍,N为常数。(二)式
2倍(二)式 减 (一)式
y-x = (2N-M) * L
所以y与x的步数差距为L倍的环。
得证。
如何确定起点0一定会进入包含key的环?
假设存在不包含key的环,起点0在不包含key的环中绕圈。
| 0 | a1 | a2 | a3 | a4 | a5 | a6 |
|---|---|---|---|---|---|---|
| b1 | b2 | b3 | b4 | b5 | b6 | b7 |
按题意不包含环,b[i]与b[j]一定不相等(i != j)
由于b1~b7从1开始,所以b[i]只能从a[j]中取(1<=i<=7,1<=j<=6)
从6个数字的集合a中取7个数字,所以假设不成立,必定存在相同数字b[k],即为key。
代码如下
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
# 如果只有两个元素,第一个元素一定是重复元素
if len(nums) == 2:
return nums[0]
# fast每次走两步,slow每次走一步,起始点可以为任意位置
fast = 0
slow = 0
# python没有do while,所以在循环外写了一遍
slow = nums[slow]
fast = nums[nums[fast]]
while slow != fast:
slow = nums[slow]
fast = nums[nums[fast]]
# fast从起点每次走一步,一定会与slow相遇,此时slow可能在环中走了多倍的L步。
# L为环一圈的步数
fast = 0
while fast != slow:
slow = nums[slow]
fast = nums[fast]
return fast
LeetCode 287. Find the Duplicate Number (python 判断环,时间复杂度O(n))的更多相关文章
- [LeetCode] 287. Find the Duplicate Number(Floyd判圈算法)
传送门 Description Given an array nums containing n + 1 integers where each integer is between 1 and n ...
- [LeetCode] 287. Find the Duplicate Number 寻找重复数
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...
- LeetCode 287. Find the Duplicate Number (找到重复的数字)
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...
- [LeetCode] 287. Find the Duplicate Number 解题思路
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...
- LeetCode : 287. Find the Duplicate Number
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAACRAAAAMMCAYAAAAhQhmZAAAMFGlDQ1BJQ0MgUHJvZmlsZQAASImVlw ...
- leetcode 217. Contains Duplicate 287. Find the Duplicate Number 442. Find All Duplicates in an Array 448. Find All Numbers Disappeared in an Array
后面3个题都是限制在1-n的,所有可以不先排序,可以利用巧方法做.最后两个题几乎一模一样. 217. Contains Duplicate class Solution { public: bool ...
- 287. Find the Duplicate Number hard
287. Find the Duplicate Number hard http://www.cnblogs.com/grandyang/p/4843654.html 51. N-Queens h ...
- 【LeetCode】287. Find the Duplicate Number 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 保存已经访问过的数字 链表成环 二分查找 日期 题目 ...
- 【LeetCode】287. Find the Duplicate Number
Difficulty:medium More:[目录]LeetCode Java实现 Description Given an array nums containing n + 1 integer ...
随机推荐
- Spring 团队开源 nohttp,尽可能不用 HTTP
Spring 团队开源 nohttp 项目,用以查找.替换和阻止 http:// 的使用. 项目是为了在可能使用 https:// 的情况下不使用到 http://,确保不会发生中间人攻击.Sprin ...
- BZOJ 1106: [POI2007]立方体大作战tet 树状数组 + 贪心
Description 一个叫做立方体大作战的游戏风靡整个Byteotia.这个游戏的规则是相当复杂的,所以我们只介绍他的简单规 则:给定玩家一个有2n个元素的栈,元素一个叠一个地放置.这些元素拥有n ...
- Xilinx 7系列FPGA部分重配置【2】
在之前的“Xilinx 7系列FPGA部分重配置[1]”中已经较为详细地记录了分别在工程模式(Project Mode)和非工程模式(Non-Project Mode)下.使用7系列的Xilinx F ...
- eas之设置单元格可编辑
for(int i=0;i<kdtEntrys.getRowCount();i++){ kdtEntrys.getRow(i).getCell("orgUnit").g ...
- HDU 2267 How Many People Can Survive(广搜,简单)
题目 //一道简单的广搜水题 #include<queue> #include<stdio.h> #include<string.h> #include<al ...
- [luogu2602 ZJOI2010] 数字计数 (数位dp)
传送门 Description 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. Input 输入文件中仅包含一行两个整数a.b,含义如上所述. Output ...
- php如何判断SQL语句的查询结果是否为空?
PHP与mysql这对黄金搭档配合的相当默契,但偶尔也会遇到一些小需求不知道该怎么做,例如今天要谈到的:如何判断sql语句查询的结果集是否为空! 我们以查询学生信息为例,来看看究竟如何实现我们的需求. ...
- NumPy常见的元素操作函数
ceil(): 向上最接近的整数,参数是 number 或 array floor(): 向下最接近的整数,参数是 number 或 array rint(): 四舍五入,参数是 number 或 a ...
- Git 基础教程 之 暂存区
工作区(working directory),就是目录,例如:pythonwork 版本库(Repository),工作区有一个隐藏的目录 .git 就是Git的版本库. 版本库最重要的是称为stag ...
- luogu P4725 多项式对数函数 (模板题、FFT、多项式求逆、求导和积分)
手动博客搬家: 本文发表于20181125 13:25:03, 原地址https://blog.csdn.net/suncongbo/article/details/84487306 题目链接: ht ...