1、二分查找框架
int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while(...) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
另外声明一下,计算 mid 时需要防止溢出,代码中 left + (right - left) / 2 就和 (left + right) / 2 的结果相同,但是有效防止了 left 和 right 太大直接相加导致溢出。
2、寻找一个基本的数
这个场景是最简单的,肯能也是大家最熟悉的,即搜索一个数,如果存在,返回其索引,否则返回 -1。
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意
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 - 1; // 注意
}
return -1;
}
3、寻找左侧边界的二分查找
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定左侧边界
right = mid - 1;
}
}
// 最后要检查 left 越界的情况
if (left >= nums.length || nums[left] != target)
return -1;
return left;
}
4、寻找右侧边界的二分查找
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定右侧边界
left = mid + 1;
}
}
// 最后要检查 right 越界的情况
if (right < 0 || nums[right] != target)
return -1;
return right;
}
5、例题
这个题相当于就是查找左侧第一个nums[i]!=i的索引,可以当成寻找左侧边界的二分查找。
class Solution {
public int missingNumber(int[] nums) {
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]==mid){
left=mid+1;
}else{
//锁定右侧边界,当left==right时,left就是左侧第一个满足条件的索引
right=mid-1;
}
}
return left;
}
}
当需要寻找右侧第一个满足条件的索引时,只需要改变一下锁定的边界。
public static int missingNumber(int[] nums) {
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]==mid){
left=mid+1;
}else{
//锁定左侧边界,当left==right时,right就是右侧第一个满足条件的索引
left=mid+1;
}
}
return left;
}