题目
https://leetcode-cn.com/problems/find-the-duplicate-number/solution/
二分查找
二分要弄清楚找的是什么,然后再确定查找的范围,然后确定如和缩小区间。
抽屉原理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。
这题我们要查找的是一个整数,改整数的范围在[1, n],由抽屉原理可知如果数组中的元素小于等于 mid 的个数 严格大于 mid 则重复元素一定在[1,mid]之间,反之在[mid+1, n]之间
所以使用二分法能确定一个范围内的整数
class Solution {
public int findDuplicate(int[] nums) {
int len = nums.length;
int left = 1;
int right = len - 1;// 重复元素的搜索范围为[1, n], n = len - 1;
while (left < right) {
int mid = left + (right - left) / 2;// mid为估测值,向下取整
int cnt = 0;
for (int num : nums) {
if (num <= mid) {
cnt++;
}
}
if (cnt > mid) { // 小于等于mid的数严格大于 mid 则重复的元素一定在[1, mid]范围内,重复元素肯能是mid自己, [1 2 3 4 4 ...] mid = 4
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
另外一种写法
class Solution {
public int findDuplicate(int[] nums) {
int len = nums.length;
int left = 1;
int right = len - 1;// 重复元素的搜索范围为[1, n], n = len - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;// mid为估测值,向上取整
int cnt = 0;
for (int num : nums) {
if (num < mid) { // 变成 <
cnt++;
}
}
if (cnt >= mid) { // 严格小于mid的数大于等于 mid 则重复的元素一定在[1, mid - 1]范围内, mid = 4 [1 2 2 3 4....]
right = mid - 1;
} else {
left = mid;
}
}
return left;
}
}