劍指offer之不修改數組找出重複數字

1. 題目

在一個長度爲n+1的數組裏的全部數字都在 1~n 的範圍內,因此數組中至少有一個數字是重複的。請找出數組中任意一個重複的數字,但不能修改輸入的數組。例如,若是輸入長度爲 8 的數組 {2,3,5,4,3,2,6,7},那麼對應的輸出是重複的數字 2 或者 3。java

2. 思路

這道題目能夠把 1~n 數字從中間的數字 m 分爲兩部分,前面一半爲 1~m,後面一半爲 m+1~n。若是 1~m 的數字的數目超過 m,那麼這一半的區間裏必定包含重複的數字;不然,另外一半 m+1~n 的區間裏必定包含重複的數字。數組

以長度爲 8 的數組 {2,3,5,4,3,2,6,7} 爲例分析查找的過程。長度爲 8 因此中間的數字爲 4,把這個數組分爲兩部分,一段是 1~4,另外一部分是 5~7。接下來統計 1~4 這 4 個數字在數組中出現的次數,它們一共出現了 5 次,所以這 4 個數字中必定存在重複的數字。code

接下來把 1~4 的範圍一分爲二,一段是 一、2 兩個數字,另外一段是 三、4 兩個數字。數字 一、2 出現了兩次,所以統計 三、4 出現的次數,它們一共出現了三次,所以存在重複的數字。再分別統計 3 和 4 出現的次數,最終輸出的結果是 3。io

3. 代碼

public int solution2(int[] numbers){
	if(numbers==null || numbers.length<=0)
		return -1;
	int start = 1;
	int end = numbers.length;
	while(start<=end){
		int mid = (start+end)/2;
		int count = countRange(numbers,start,mid);
		if(start==end){
			if(count>1)
				return start;
			else
				break;
		}
		if(count>(mid-start+1))
			end = mid;
		else
			start = mid+1;
	}
	return -1;
}
private int countRange(int[] numbers,int start,int end){
	int count = 0;
	for(int i=0;i<numbers.length;i++){
		if(numbers[i]>=start && numbers[i]<=end)
			count++;
	}
	return count;
}
相關文章
相關標籤/搜索