Find the Duplicate Number
要点:通过Pigeonhole principle对值空间做binary search,具体来说,
- low,mid,high都是值空间,所以范围是[1,n]。注意鸽巢原理是positive:也就是多出来的必有重复。所以如果[1,mid]之间的元素cnt>mid,那么duplicate在[1,mid]内。
- 那么negative成立吗?也就是说cnt<=mid,[1,mid]就没有duplicate吗?首先鸽巢原理对negative是不适用的,但是这题有只有一个duplicate的假设。所以如果[1,mid]的cnt<=mid,那么[mid+1,n]之间的元素cnt一定>n-mid(因为总共n+1,所以>=n+1-mid)。所以是二选一。
- 这里用了小技巧high初始为n-1,这样最后的落点low可以为n。同样的,每次cnt>mid的情况,high=mid-1把mid skip了。最终的low还可能落在mid上
- 这题还有两指针的O(n)算法,略过。
class Solution(object):
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
low, high = 1, len(nums)-1
while low<=high:
mid = low + (high-low)/2
cnt=0
for i in nums:
if i<=mid:
cnt+=1
if cnt>mid:
high = mid-1
else:
low = mid+1
return low