整数二分
框架
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 代替 mid = (left + right)/2;加快速度:使用left+right>>2
开闭区间的选择
- right的赋值:nums.length - 1(对应闭区间) 还是 nums.length(开区间)
- while的循环条件(当搜索区间为空时结束循环):<=(闭区间)还是 <(开区间)
- left、right的重新赋值(mid搜索过,从搜索区间去除):right = mid - 1 还是 right = mid 等
基本的二分搜索(寻找一个数)
缺陷:无法查找目标的左右边界
寻找左/右侧边界的二分搜索
寻找左侧边界时,找到 target 时不要立即返回,而是缩小「搜索区间」的上界right,在区间[left, mid]中继续搜索,即不断向左收缩,达到锁定左侧边界的目的
同理寻找右侧边界时要收紧下边界以锁定目标的右侧边界
注意:因为此时返回的是left或right下标,所以需要注意算法可能出现越界或nums[left] != target情况,需要在返回时校验
public static int binarySearchLeft(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid;
while (left <= right) {
mid = left + right >> 1;
if (nums[mid] < target) left = mid + 1; //如果只有数组中一个该元素,返回的left会再次加到该位置
else right = mid - 1;
}
if (left >= nums.length || nums[left] != target) return -1;
else return left;
}
public static int binarySearchRight(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid;
while (left <= right) {
mid = left + right >> 1;
if (nums[mid] > target) right = mid - 1;
else left = mid + 1;
}
if (right < 0 || nums[right] != target) return -1;
else return right;
}
二分查找应用
问题函数抽象为类似下图形式 ==> 对自变量进行二分搜索,因变量作为判断
leetcode
- 704
- 34
- 875:函数抽象
- 1011
- 410:本题可等价替换为1011题
浮点数二分
不需处理边界
计算机浮点数存在误差,计算时求的精度一般比要求精度多两位