二分查找总结
二分查找-红蓝染色法总结
二分查找-红蓝染色法
L, R分别指向数组的左右边界及闭区间[L,R],红色背景表示不满足条件,蓝色表示满足条件,白色表示不确定
开闭区间问题
闭区间(常用):[0, nums.length - 1] 退出二分查找需要left <= right, 移动区间时 left = mid + 1, right = mid - 1,这样才不会出现死循环。
左闭右开:[0, nums.length) 退出二分查找需要left < right, 移动区间时 left = mid + 1, right = mid
开区间:(-1, nums.length) 退出二分查找需要left+1 < right, 移动区间时 left = mid, right = mid
34.在排序数组中查找元素的第一个和最后一个位置
思想:使用二分查找去查找target的第一个位置,如果第一个满足位置是数组长度说明整个数组都是红色,或者返回的值不等于target,不符合条件。再使用二分查找去找target+1的前一个位置。
二分查找(红蓝染色)的思想:利用数组有序的性质,从左右两端开始快速查找符合的target范围,如果nums[mid]小于target,left=mid+1,从右侧开始查找,反之亦然,找到符合条件的第一个target位置
1 | class Solution { |
非>= k 问题如何转化(在有序数组问题中)
“>k”可以看作是>= k+1
“<k”可以看作 (>=k) -1,即找到大于等于k的位置的前一个位置
“<=k”可以看作(>k) -1,即找到大于k的位置的前一个位置
162.寻找峰值
蓝色是峰值及其右侧,right = nums.length - 1, nums[right]一定是蓝色,预留这个位置
每次二分确定一半的颜色
简单来说就是当有nums[mid] > nums[mid + 1]就能确定是一个下坡,至少有一个峰值,如果nums[mid]之前是上坡,那么nums[mid]就是峰值,nums[mid]之前是下坡,也能确定一个峰值
1 | class Solution { |
153. 寻找旋转排序数组中的最小值
red:最小值左侧
blue:最小值及其右侧
5 6 7 8 2 3 4
num[right]一定是蓝色,大于等于num[right]肯定要舍弃染成红色,最小值肯定小于num[right],选择左侧区域寻找
1 | class Solution { |
154. 寻找旋转排序数组中的最小值 II
本题与 153 的区别在于有相同元素,这会导致在二分查找时,可能会遇到「恰好」二分元素与数组末尾元素相同的情况,此时无法确定答案在左半区间还是右半区间。
我们接着 153 题解 的代码来实现。本题需要稍加修改,改为与区间右端点处的元素比较(如果你写的是闭区间的话,那就是与右端点 +1 的元素比较)。
在遇到相同元素时,既然无法确定最小值所在区间,那么干脆去掉末尾元素,继续二分。对应到代码上,就是 right 减一
你可能会有疑问:这样做不会碰巧把最小值给去掉吗?这是不会的:
- 如果末尾元素就是最小值,那么nums[mid] 也是最小值,说明最小值仍然在二分区间中;
- 如果末尾元素不是最小值,这样做相当于排除了一个错误答案。
1 | class Solution { |
33. 搜索旋转排序数组
red:目标target左侧
blue:目标target及其右侧
当nums[mid]>end时,在左侧:
- nums[mid ] > target 可以缩小蓝色区间, right=mid
当nums[mid]<end时,在右侧:
- 当nums[mid]已经在右侧,target>end说明target还在左侧,即可缩小蓝色区间
- 当nums[mid] > target,与第一种情况同理
1 | class Solution { |