Find the Duplicate Number
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Note:
O(n2)
.分析:
給定一個數組,數組長度為n+1,裡面的數都在1和n之間,這樣,數組裡肯定有一個數是出現兩次的。假定只有一個數字重復了,找出那個重復數。
要求:數組不可修改,只讀;只能使用常數個空間;算法復雜度要小於O(n^2),即不能暴力;假定那個重復數只有一個,但是可以出現許多次。
這題想了好久沒想出來。查看了Discuss才明白。
第一種解法:
使用弗洛伊德循環檢測法,記得昨天才寫了一題叫Linked List Cycle,這題就是用該檢測法寫出來的。
思路是,根據數組元素的特點,將數組元素與下標一一映射起來。比如數組是13422,則0對應1,1對應3,2對應4等。這樣,如果將這種映射當成鏈的話,可以順著下標,下標對應的值,下標對應值的對應下標的值,一直遍歷,鏈中有環,則最後一定會進行循環中,比如對於上面的數組,最後陷入了循環下標2對應值4,下標4對應值2,下標2對應值4,如此循環。
單單找到了循環還不夠,我們還需要找到進入循環的那個數字,它才是要找的重復數。可以重新用一個下標為0的值從頭開始映射,這樣與前面循環中的指針相遇時,找到的就是循環的起點。
代碼1:
class Solution(object): def findDuplicate(self, nums): :type nums: List[int] :rtype: int slow, fast = 0, 0 while True: slow = nums[slow] fast = nums[nums[fast]] if slow == fast: break # fast和slow一定在循環中某點相遇了,但是相遇的點不一定是剛剛進入循環的那個元素, # 需要從0開始繼續尋找 find = 0 while find != slow: slow = nums[slow] find = nums[find] return find
第二種解法:
使用二分法。
代碼:
class Solution(object): def findDuplicate(self, nums): :type nums: List[int] :rtype: int l, r = 0, len(nums) - 1 while l <= r: mid = l + (r - l) / 2 cnt = 0 for n in nums: if n <= mid: cnt += 1 if cnt > mid: r = mid - 1 else: l = mid + 1 return l