原题网址:https://leetcode.com/problems/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:
- 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.
方法一:应用鸽笼原理进行二分法查找。
因为在1~n的范围内最多只能放n个不同的数字,但现在数组放了n+1个数字,所以至少有一个重复。
对于在1~n范围内的某个数字m,那么数组中小于等于m的数字最少有m个,并且刚好为m的时候,1~m之间不会有重复,为什么呢?我们分开来证明。
public class Solution {
public int findDuplicate(int[] nums) {
int low = 1, high = nums.length-1;
while (low<high) {
int mid = (low+high)/2;
int count = 0;
for(int num: nums) if (num<=mid) count++;
if (count > mid) high = mid; else low = mid + 1;
}
return low;
}
}
方法二:循环链条检测法。这个方法我没有想出来,网上找到的,使用的技术竟然和循环链表检测的方法一模一样!
public class Solution {
public int findDuplicate(int[] nums) {
int slow = 0, fast = 0;
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (nums[slow] != nums[fast]);
int restart = 0;
while (nums[restart] != nums[slow]) {
restart = nums[restart];
slow = nums[slow];
}
return nums[restart];
}
}
参考文章:
http://bookshadow.com/weblog/2015/09/28/leetcode-find-duplicate-number/
https://segmentfault.com/a/1190000003817671