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.
M1: 在0~n-1范围内,遍历数组。如果nums[abs(nums[i])] >= 0,把它变成小于0;如果< 0,则该数为重复数
时间O(N),空间O(1)
class Solution { public int findDuplicate(int[] nums) { int i; for(i = 0; i < nums.length; i++) { if(nums[Math.abs(nums[i])] >= 0) nums[Math.abs(nums[i])] = - nums[Math.abs(nums[i])]; else break; } return Math.abs(nums[i]); }}
M2: 用binary search,对于由1~n构成的数组,数组长度(nums.length = n + 1)总大于数组里的任意数字,mid = length/2。如果每个数只出现一次,那么必然在mid两边有相同数量的数。如果某一边多了,说明重复的数在这边,可以缩小范围。
从index为1的元素开始统计比较方便。从1~lengh-1,mid是中位数,遍历数组统计<= mid的元素个数cnt,如果没有重复数,<= mid的个数应该大于mid(=mid+1)。在已知存在重复数的情况下,如果<= mid的元素个数<= mid,说明重复数在右侧,l = mid+1;如果>mid,说明在左侧,r = mid。不断重复直到 l >= r,最后的 l 就是答案。
时间O(NlogN),空间O(1)
class Solution { public int findDuplicate(int[] nums) { int l = 1, r = nums.length - 1; while(l < r) { int mid = l + (r - l) / 2, cnt = 0; for(int i : nums) { if(i <= mid) cnt++; } if(cnt <= mid) l = mid + 1; else r = mid; } return l; }}