LeetCode 287. Find the Duplicate Number (时间复杂度O(n)) + 链表判断环
LeetCode 287. Find the Duplicate Number
暴力解法
時(shí)間 O(nlog(n)),空間O(n),按題目中Note“只用O(1)的空間”,照理是過(guò)不了的,但是可能判題并沒(méi)有卡空間復(fù)雜度,所以也能AC。
class Solution:# 基本思路為,將第一次出現(xiàn)的數(shù)字def findDuplicate(self, nums: List[int]) -> int:s = set()for i in nums:a = i in sif a == True:return ielse:s.add(i)雙指針判斷環(huán)
時(shí)間O(n),空間O(1),思路十分巧妙,但是使用條件比較苛刻。根據(jù)題目給出的條件,恰好能用這種解法,這應(yīng)該也是出題人推薦的解法。
題意分析:
注:上面所說(shuō)的環(huán)是指1->2->3->1
以樣例1為例:[1,3,4,2,2]
| 1 | 3 | 4 | 2 | 2 |
如下圖所示,其中2->4->2構(gòu)成環(huán),入環(huán)點(diǎn)為2
解題思路
由題意分析可知,每個(gè)樣例都可以畫成這樣一張圖,我們只需要找出圖中的環(huán),并找出入環(huán)點(diǎn),即為所求的重復(fù)數(shù)字key,下面都用key表示所求的重復(fù)數(shù)字。
為什么必定存在環(huán)
以樣例1為例,圖中出現(xiàn)了5個(gè)點(diǎn)0-4,圖中存在5根指針線,5個(gè)點(diǎn)5根線,必定存在環(huán)。
n個(gè)點(diǎn),點(diǎn)的范圍去0~n-1,n根線,必定存在環(huán)。(n-1根線是恰好無(wú)環(huán)的情況,自己畫圖可知)
找環(huán)的方法
設(shè)置一個(gè)慢指針slow,一個(gè)快指針fast。slow每次走一步,fast每次走兩步,如果slow與fast能相遇,說(shuō)明圖中存在環(huán),并且相遇點(diǎn)一定存在于環(huán)中。
為什么key一定為入環(huán)點(diǎn)?
有題意分析中的表可知,key的入度一定大于1,即不止一個(gè)點(diǎn)可以直接到key。而key一定存在于環(huán)中,所以key一定為入環(huán)點(diǎn)。樣例1中3,4都可到達(dá)2,2的入度2,2為入環(huán)點(diǎn),即為所求的key。
怎么找入環(huán)點(diǎn)key?
slow和fast相交的點(diǎn)記為相遇點(diǎn)P。
slow和fast從起點(diǎn)0到相遇點(diǎn)P運(yùn)行步驟如下:
這個(gè)相遇點(diǎn)P與起點(diǎn)0到達(dá)入環(huán)點(diǎn)key的步數(shù) 差距為環(huán)L的整數(shù)倍,故設(shè)置slow2從起點(diǎn)0開始,每次走一步,slow從相遇點(diǎn)P開始,每次走一步,slow和slow2一定會(huì)相遇在入環(huán)點(diǎn)key。
我們可以有一個(gè)小小的證明,如下圖
設(shè)起點(diǎn)0到達(dá)入環(huán)點(diǎn)key的步數(shù)為x,相遇點(diǎn)P到達(dá)入環(huán)點(diǎn)key的步數(shù)為y。
設(shè)slow指針走到相遇點(diǎn)P的步數(shù)為t,fast走到相遇點(diǎn)P的步數(shù)為2*t。
設(shè)走完環(huán)一圈的步數(shù)為L(zhǎng)
2 * t - x + y = M * L(一)
t - x + y = N * L (二)
fast指針在環(huán)中走的步數(shù)2t-x,此時(shí)到達(dá)相遇點(diǎn)P,key->P->key步數(shù)為2t-x+y = M * L,正好為L(zhǎng)的M倍,M為常數(shù)。(一)式
slow指針在環(huán)中走的步數(shù)t-x,此時(shí)到達(dá)相遇點(diǎn)P,key->P->key步數(shù)為t-x+y = N * L,正好為L(zhǎng)的N倍,N為常數(shù)。(二)式
2倍(二)式 減 (一)式
y-x = (2N-M) * L
所以y與x的步數(shù)差距為L(zhǎng)倍的環(huán)。
得證。
如何確定起點(diǎn)0一定會(huì)進(jìn)入包含key的環(huán)?
假設(shè)存在不包含key的環(huán),起點(diǎn)0在不包含key的環(huán)中繞圈。
| b1 | b2 | b3 | b4 | b5 | b6 | b7 |
按題意不包含環(huán),b[i]與b[j]一定不相等(i != j)
由于b1~b7從1開始,所以b[i]只能從a[j]中取(1<=i<=7,1<=j<=6)
從6個(gè)數(shù)字的集合a中取7個(gè)數(shù)字,所以假設(shè)不成立,必定存在相同數(shù)字b[k],即為key。
代碼如下
class Solution:def findDuplicate(self, nums: List[int]) -> int:# 如果只有兩個(gè)元素,第一個(gè)元素一定是重復(fù)元素if len(nums) == 2:return nums[0]# fast每次走兩步,slow每次走一步,起始點(diǎn)可以為任意位置fast = 0slow = 0# python沒(méi)有do while,所以在循環(huán)外寫了一遍slow = nums[slow]fast = nums[nums[fast]]while slow != fast:slow = nums[slow]fast = nums[nums[fast]]# fast從起點(diǎn)每次走一步,一定會(huì)與slow相遇,此時(shí)slow可能在環(huán)中走了多倍的L步。# L為環(huán)一圈的步數(shù)fast = 0while fast != slow:slow = nums[slow]fast = nums[fast]return fast總結(jié)
以上是生活随笔為你收集整理的LeetCode 287. Find the Duplicate Number (时间复杂度O(n)) + 链表判断环的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python3遍历选中文件夹下的文件【G
- 下一篇: 【读书笔记】2015年考研英语二真题翻译