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.
Example 1:
Input: [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2] Output: 3
Note:
- You must not modify the array (assume the array is read only).
- You must use only constant, O(1) extra space.
- Your runtime complexity should be less than O(n2).
- There is only one duplicate number in the array, but it could be repeated more than once.
-------------------------------------------------------------
这题限制条件比较多,如果不仔细看题,会出各种问题,每一个note都有用,但是自己的思路还是太慢了,最后想到二分并不难,但是还写了一个bug,上一下O(nlog(n))的代码。
class Solution:
def count_occurance(self, nums, target):
less,equal,larger = 0,0,0
for num in nums:
if (num == target):
equal += 1
elif (num < target):
less += 1
else:
larger += 1
return less, equal, larger
def findDuplicate(self, nums):
nl = len(nums)
l,r = 1,nl-1
while (l <= r):
mid = ((r-l)>>1)+l
less, equal, larger = self.count_occurance(nums, mid)
if (equal > 1):
return mid
elif (larger > nl-(mid+1)): #bug1: written as larger > less
l = mid + 1
else:
r = mid - 1
s = Solution()
print(s.findDuplicate([4,3,1,4,2]))
Discussion还有一种非常好的O(n)的思路,就是把这个数组理解成一个有环的列表:
# x_0 -> x_1 -> ... x_k -> x_{k+1} ... -> x_{k+j}
# ^ |
# | |
# +-----------------------+
class Solution:
def findDuplicate(self, nums):
# Find the intersection point of the two runners.
tortoise = nums[0]
hare = nums[0]
while True:
tortoise = nums[tortoise]
hare = nums[nums[hare]]
if tortoise == hare:
break
# Find the "entrance" to the cycle.
ptr1 = nums[0]
ptr2 = tortoise
while ptr1 != ptr2:
ptr1 = nums[ptr1]
ptr2 = nums[ptr2]
return ptr1