Leetcode 287:尋找重複數(最詳細的解法!!!)
給定一個包含 n + 1 個整數的陣列 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重複的整數。假設只有一個重複的整數,找出這個重複的數。
示例 1:
輸入: [1,3,4,2,2]
輸出: 2
示例 2:
輸入: [3,1,3,4,2]
輸出: 3
說明:
- 不能更改原陣列(假設陣列是隻讀的)。
- 只能使用額外的 O(1) 的空間。
- 時間複雜度小於 O(n2) 。
- 陣列中只有一個重複的數字,但它可能不止重複出現一次。
解題思路
我們首先想到的解法就是現將陣列nums
排序,建立pre
和cur
nums
從頭到尾的遍歷,判斷nums[pre]==nums[cur]
,如果成立,返回nums[pre]
即可,否則的話繼續遍歷。
class Solution:
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums.sort()
for i in range(len(nums)-1):
if nums[i] == nums[i+1]:
return nums[i]
但是我們這種做法改變了原有的陣列,所以這種做法就被我們排除了。由於是查詢問題,我們不難想到通過二分搜尋法,但是這裡我們要將原來的二分搜尋法做一些調整。我們首先計算mid
,然後我們統計陣列中小於等於mid
元素的個數k
,如果k<=mid
的話,那麼說明重複值在[mid+1,n]
之間,否則的話重複值在[1,mid]
之間。為什麼這樣子做是合理的呢?實際上這個問題的思想來源於抽屜原理,我們將包含重複元素的所有數放到一個可以容納所有數的陣列中去,如下
1 2 3 4 __________ 1 2 3 4 2
如果採用下整除策略,此時我們的mid=2
,我們發現此時左邊元素個數大於右邊元素個數,這就是由於重複元素造成的兩邊不平衡,如果沒有重複元素,兩邊數的個數應該是一樣的。我們現在再回到我們的演算法,看它是怎麼和抽屜原理聯絡起來的。
1 3 4 2 2
mid=2
我們此時的mid=2
(也就是中間抽屜的位置),我們接著統計小於等於2
的數的個數(統計抽屜左邊元素個數),也就是k=3
,而3>2
,所以我們在[1,2]
這個區間中找重複元素(抽屜左邊找重複元素),再次計算mid=1
,我們發現k=1<=1
,此時我們就知道了2
即為重複元素。
class Solution:
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
low, high = 1, len(nums)-1
while low < high:
mid = (high+low)//2
count = sum(num <= mid for num in nums)
if count <= mid:
low = mid+1
else:
high = mid
return low
這個問題有一個非常巧妙的解法,我們看上面的例子
1 3 4 2 2
如果我們使用t=nums[t]
這樣的前進方式,我們首先令t=0
t=nums[0]=1
t=nums[1]=3
t=nums[3]=2
t=nums[2]=4
t=nums[4]=2
t=nums[2]=4
...
我們發現進入了迴圈。我們再使用t=nums[nums[t]]
這樣的前進策略
t=nums[nums[0]]=3
t=nums[nums[3]]=4
t=nums[nums[4]]=4
....
其實就是比前面快了一倍。這就變成了之前Leetcode 142:環形連結串列 II(最詳細的解法!!!)的問題,我們可以使用快慢指標解決。
class Solution:
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) > 1:
slow = nums[0]
fast = nums[nums[0]]
while slow != fast:
slow = nums[slow]
fast = nums[nums[fast]]
entry = 0
while entry != slow:
entry = nums[entry]
slow = nums[slow]
return entry
return -1
講道理,這種洞察力真的太厲害了。
reference:
http://keithschwarz.com/interesting/code/?dir=find-duplicate
我將該問題的其他語言版本新增到了我的GitHub Leetcode
如有問題,希望大家指出!!!