思路很简单,细节是魔鬼。
注意:搜索区间,函数返回值的取值区间。
寻找一个数(基本的二分查找)
搜索一个数,如果存在,返回其索引,否则返回-1。
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意1
while(left <= right) { // 注意2
int mid = left + (right - left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意3
else if (nums[mid] > target)
right = mid - 1; // 注意4
}
return -1;
}
-
搜索区间是闭区间 [left, right]
-
循环终止条件是:搜素区间为空。
因为搜素区间是闭区间,所以循环终止条件是 left > right,否则 [left,left]区间不为空。 -
向右收缩搜索区间时,mid已经比较过了,因为搜索区间是闭区间,所以需要+1。
-
向左收缩搜索区间时,mid已经比较过了,因为搜索区间是闭区间,所以需要-1。
寻找左侧边界的二分查找
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0;
int right = nums.length; // 注意1
while (left < right) { // 注意2
int mid = left + (right -left) / 2;
if (nums[mid] == target) {
right = mid; // 注意3
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid; // 注意3
}
}
if(left != nums.length && nums[left] == target){
return left; // 注意4
}
return -1;
}
-
搜索区间是左闭右开区间 [left, right)
-
循环终止条件是:搜素区间为空。
因为搜素区间是左闭右开区间,所以循环终止条件是 left = right 。 -
向左收缩搜索区间时,mid已经比较过了,因为搜索区间是左闭右开区间,所以将mid的值赋给right。
-
函数的返回值(即 left 变量的值)取值区间是闭区间 [0, nums.length],所以我们简单添加两行代码就能在正确的时候 return -1
寻找右侧边界的二分查找
与寻找左边界基本相同
int right_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length; // 注意1
while (left < right) { //注意2
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
left = mid + 1; // 注意3
} else if (nums[mid] < target) {
left = mid + 1; // 注意3
} else if (nums[mid] > target) {
right = mid;
}
}
if (left != 0 && nums[left-1] == target){
return left -1; //注意3
}
return -1;
-
搜索区间是左闭右开区间 [left, right)
-
循环终止条件是:搜素区间为空。
因为搜素区间是左闭右开区间,所以循环终止条件是 left = right 。 -
向右收缩搜索区间时,mid已经比较过了,因为搜索区间是左闭右开区间,所以+1。
-
left 取值区间是闭区间 [0, nums.length],返回值是left -1,所以我们简单添加两行代码就能在正确的时候 return -1
详细讲解参考:详解二分查找算法