框架
二分查找特别容易出现问题,尤其发生在寻找左右边界的情况
主要注意这几点:
- 计算mid的时候使用
left + (right - left) / 2
防止溢出 - 不写else,而是用if把条件说明
- 明确自己的搜索区间,跳出while的条件就是搜索区间长度为0
- 注意left、right和mid之间的关系,尤其是right的初始值情况
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length; // 注意
while(left < right) {
int mid = left + (right - left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意
else if (nums[mid] > target)
right = mid; // 注意
}
return -1;
}
左边界查找
查找左边界时找到 target 时不是立即返回,而是缩小「搜索区间」的上界 right
,达到锁定左边界的目的
而因为不是立即返回,如果出现target
大于所有数的情况,left最后会等于初始的right退出循环,所以我们return之前要检查
int left_bound(int[] nums, int target) {
int left = 0;
int right = nums.Length; // 注意
while (left < right) { // 注意
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意
}
}
// 判断 target 是否存在于 nums 中
// 此时 left 索引越界
if(left == nums.Length) return -1;
// 判断一下 nums[left] 是不是 target
else return nums[left] == target ? left : -1;
}
左边界查找
只有两处和搜索左侧边界不同
返回的是left - 1
(此时right == left
,right - 1
也一样)
一处是right在target小于所有数时会等于left, 而返回的是left - 1
,数组越界
int right_bound(int[] nums, int target) {
int left = 0;
int right = nums.Length; // 注意
while (left < right) { // 注意
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
left = mid + 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意
}
}
// 判断 target 是否存在于 nums 中
// 此时 left - 1 索引越界
if (left - 1 < 0) return -1;
// 判断一下 nums[left] 是不是 target
return nums[left - 1] == target ? (left - 1) : -1;
}