题目要求
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
使用二分查找的思路
思路:
- 由于整数数组nums的长度是 n + 1, 而nums[i] 的范围在[1,n] 所以一定存在重复整数。
- 将 1 - n 范围内的数组以中间数字m分为两部分,分别为 (1,m) 与 (m + 1 , n)
- 统计(1,m) 的数字在数组nums中出现的次数 count,若 count 大于 m,则说明重复的数字一定在(1,m) 中出现。反之在(m+1,n) 中出现。
- 若重复的数字在(1,m)中出现,则继续将(1,m)一分为二,重复执行第三步。
class Solution {
public int findDuplicate(int[] nums) {
if (nums.length == 0) {
return -1;
}
int N = nums.length;
int start = 1;
int end = N - 1;
while (start <= end) {
int mid = (start + end) / 2;
// 计算在 1 - mid 范围内nums中元素的个数,若数目大于m,则重复数字一定在(start,end)中,否则一定在(mid + 1, end)中,所以只需要计算一次即可(这里选择计算(1,m)内的数目)
int count = countInScope(nums,start,mid);
// 查看是否找到
if (start == end) {
if (count > 1) {
return start;
} else {
return -1;
}
}
// 重复数字在 (start,mid) 内
if (count > mid - start + 1) {
end = mid;
} else { // 重复数字在(mid + 1, end)内
start = mid + 1;
}
}
return -1;
}
private int countInScope(int[] nums, int start, int end) {
int count = 0;
int N = nums.length;
for (int i = 0; i < N; i++) {
if (nums[i] >= start && nums[i] <= end) {
count++;
}
}
return count;
}
}