算法笔记——二分查找
点击阅读更多查看文章内容
算法笔记——二分查找
二分查找:用于在有序数列中查找目标元素的位置
关于区间边界的问题
二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
左闭右闭
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1,因为寻找区间是左闭右闭,所以right必须更新为middle-1而不是middle
左闭右开
- while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,middle不包含在区间内
如果可以自己选择区间的话建议使用左闭右闭区间
关于查找的值的问题
这里查找目标值有三种情况
- 查找给定值
- 查找小于等于给定值的最大值
- 查找大于等于给定值的最小值
1.查找给定值
这个比较简单,直接上代码
具体实现细节写在注释中
1 | int BinarySearch(vector<int> nums, int target) |
2.查找小于等于给定值的最大值
1 | int LowerTarget(vector<int> nums, int target) |
这里有三个点需要注意
while(left<right)
int mid=left+(right-left+1)/2
if(nums[mid]<=target) left=mid
具体原因在代码注释中已经写清楚了,第一第三点比较好理解,第二点可以自己带入一组数据试一下
如:在[1,9,25]中找小于等于10的最大值
如果不加第二点
- left=0,right=2
- mid=1,nums[mid]=9,9<target,left=mid=1
- left=1,right=2;mid=1出现死循环
加上第二点后
- left=0,right=2
- mid=1,nums[mid]=9,9<target,left=mid=1
- left=1,right=2,mid=2,nums[mid]=25>target,right=mid-1=1
- left=right 退出循环
3.查找大于等于给定值的最小值
这个与上一个类似,对比上一个看即可
1 | int UpperTarget(vector<int> nums, int target) |
关于C++内置函数的使用
C++中有两个内置函数lower_bound和upper_bound,都是使用二分查找实现的
lower_bound
在从小到大的排序数组中:
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
在从大到小的排序数组中,重载lower_bound():
lower_bound( begin,end,num,greater
核心代码:
1 | while (left < right) |
upper_bound
在从小到大的排序数组中:
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
在从大到小的排序数组中,重载upper_bound():
upper_bound( begin,end,num,greater
核心代码:
1 | while (left < right) |
使用方法
1 | vector<int> nums1{1, 3, 5, 7}; |