翻了一下自己的博客。记录了花花酱的二分搜索模板、王争的二分搜索模板。
花花酱的文章中提到:不要试图去找一个正确答案。试图去找一个分割点m,使得x>=m,g(x)>0为true。这个始终get不到。
王争的二分模板思路是比较简单的,就是时间长了,忘记了。考虑边界值的时候,是在代码逻辑中考虑,容易理解。
接下来记录一下labuladong的二分搜索模板。
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;
}
2 查找目标值的左边界
查找目标值的左边界,也就是第一个等于目标值的位置。
int left_bound(int[] nums, int target) {int left = 0, right = nums.length - 1;// 搜索区间为 [left, right]while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] < target) {// 搜索区间变为 [mid+1, right]left = mid + 1;} else if (nums[mid] > target) {// 搜索区间变为 [left, mid-1]right = mid - 1;} else if (nums[mid] == target) {// 收缩右侧边界right = mid - 1;}}// 检查出界情况,因为退出条件是left=right+1if (left >= nums.length || nums[left] != target)return -1;return left;
}
左侧边界的含义是:数组中<target的数有多少个,取值区间是[0,nums.length]
如果target<nums中的任何元素,那么在整个搜索过程中right会不断变小,left=0,所以此时退出条件是right<=-1。因为该方法中返回的是left,所以不需要检查边界。
如果target>nums中的任何元素,那么在个搜索过程中left会不断变大,所以此时的退出条件是left>=nums.length。因为该方法中返回的是left,这个时候left会越界,所以需要检查。
3 查找目标值的右边界
查找目标值的右边界,也就是最后一个等于目标值的位置。
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;
}
因为当nums[mid] == target的时候,修改的是left,那退出循环的时候left指向的可能nums[left]不等于target,所以检测right。
那这个时候right一定指向nums[right]=target吗?