题意:
有一个大小是n+1的数组。数组的元素都是[1, n]区间内的数字。必有且仅有一个数字重复(可能重复不止一次),找出这个数字
分析:
这个题的数字很有特色,数字都小于最大角标,就给了利用角标的机会。但怎么利用呢,画画想想之后突然想到是不是可以利用值做角标再用得到的值再做角标,这样必定有一个循环。因为这个循环,想到使用双指针,但是之后存在什么规律就没什么规律了。所以只好考虑另一种方法,(抽屉原理)因为本来是1 2 3 4 5 6 7...每个一个,但是这个题目的核心之处在于,比如2有两个(核心特征一般化),则必然可以推出这个数组不均匀了(左半比右半多了一个),所以可以确定这个数在多的那一边,所以二分查找:
public class Solution {
public int findDuplicate(int[] nums) {
int low = 1;
int high = nums.length -1;
int mid = 0;
while(low<high) {
mid = low + (high-low)/2;
int c = com(nums, mid);
if(c > mid) { //比如小于等于4的数有5个,那就应该查1到4
high = mid;
}else{ //比如小于等于4的数的个数是4个或者更少,应该查5到7
low = mid+1;
}
}
return low;
}
private int com(int[] nums, int mid) {
int count = 0;
for(int i=0; i < nums.length; i++){
if(nums[i] <= mid)
count++;
}
return count;
}
}