直接上代码
public class BinarySearch {
/*
二分搜索的注意点有:
1、左右下标的取值范围,会有 r = nums.length 和 r = nums.length - 1 两种写法
2、循环结束条件,会有 l < r 和 l <= r 两种写法,决定是否在循环结束补充判断
3、根据二分搜素的目的不同,在更新l和r时会有不同
4、为了我自己的记忆不混乱,统一采用 int l = 0, r = nums.length - 1 和 while(l <= r) 写法
*/
// 顾名思义,找到第一次碰到的目标值位置下标,如果不存在目标值返回-1
public int firstBinarySearch(int[] nums, int target){
int l = 0, r = nums.length - 1;
// 一般用,l<=r,这样不用再循环结束时对nums[l]进行判断
while(l <= r){
int m = l + (r - l) / 2;
if(nums[m] == target){
return m;
}else if(nums[m] < target){
l = m + 1;
}else {
r = m - 1;
}
}
// 循环内无返回,即没找到
return -1;
}
// 顾名思义,找到最左边目标值位置下标,如果不存在目标值返回-1
public int leftBinarySearch(int[] nums, int target){
int l = 0, r = nums.length - 1;
// 一般用,l<=r,这样不用再循环结束时对nums[l]进行判断
while(l <= r){
int m = l + (r - l) / 2;
if(nums[m] == target){
// 如果已经找到了目标值,因为要找最左边的,将右指针移动过来,向左搜索
// 为了结束死循环,使r = m - 1,而不是r = m
r = m - 1;
}else if(nums[m] < target){
l = m + 1;
}else {
r = m - 1;
}
}
// 因为循环内无返回语句,要在结束时判断情况
if(l == nums.length)//情况2
return -1;
return nums[l] == target ? l : -1;
}
// 顾名思义,找到最右边目标值位置下标,如果不存在目标值返回-1
public int rightBinarySearch(int[] nums, int target){
int l = 0, r = nums.length - 1;
// 一般用,l<=r,这样不用再循环结束时对nums[l]进行判断
while(l <= r){
int m = l + (r - l) / 2;
if(nums[m] == target){
// 如果已经找到了目标值,因为要找最右边的,将左指针移动过来,向右搜索
// 为了结束死循环,使l = m + 1,而不是l = m
l = m + 1;
}else if(nums[m] < target){
l = m + 1;
}else {
r = m - 1;
}
}
if(l == 0)
return -1;
return nums[l - 1] == target ? l - 1 : -1;
}
}
总结:左右边界的二分搜索,无非是在遇到目标值时向左向右收缩边界而不是直接返回,不直接返回我们则要在循环结束对当前情况进行判断返回什么,同时还要去判断指针是否越界;循环结束的条件是r+1=l;只要明确各种情况做好边界处理就能正确写出代码。