概述
- 二分查找分三种
- 查找某个确定的值
- 查找左边界
- 查找右边界
- 本质
- 二分的本质是缩小区间
- 难点:
- 最难的点在于大于小于符号的界定,有多种写法,单纯记很难,这里做一次总结
规定
- 这里限定几个规定,按照这种套路写
// 左右都是闭区间
left = 0, right = nums.length-1;
// while(left <= right) 后面条件都是
while(left <= right)
查找确定值
- 退出条件是 right 在 left 的左边, 这时候就是不存在这个值
int binary_search(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) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
查找左边界
- 同样基本上和查找某个值框架相同
- 两个不同点
-
等于条件时候, right = mid -1,这个直接画个图就直到呢
-
记住一点 二分的本质是缩小区间
-
需要判断越界情况
-
- 为什么返回的是 left 而不是 right ,看图,退出循环条件是 left> right
- 为什么 相等条件的时候是 right = mid - 1, 如图所示
- 由于我们确定的都是闭区间 [0,nums.length-1] ,所以必然是 left = mid+1 或者right= mid-1,
- 如果选定的是闭区间, 在相等情况下 left = mid 或者是 right = mid ,会导致不能退出循环
- 所以在相等情况下,肯定是 left = mid +1 或者是 right = mid -1
- 我们知道,二分查找的本质是排除掉不需要的区间
- 如果 选定的是 left = mid + 1,那么 left 将指向 第二个 2 的位置,下一次循环,left 将指向 3 所在的位置,而我们需要排除的就是右侧的区间,所以用脚丫子想都知道是错的(这是排除左侧的区间,找的是右侧的边界)
- 所以 找左侧边界,nums[mid] = target 相等时候 是 right = mid -1 ,排除右侧无用区间
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;
}
右边界
- 和左边界基本上完全相同的代码,就是相等排除的是左侧区间
- 记住需要这边需要返回的是right
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;
}