5.二分搜索
二分搜索
《算法小抄》作者 labuladong 一首诗
二分查找框架
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 ...;
}
分析二分查找的一个技巧是:不要出现 else,而是把所有情况用 else if 写清楚,这样可以清楚地展现所有细节。
另外声明一下,计算 mid 时需要防止溢出,代码中left + (right - left) / 2
就和(left + right) / 2
的结果相同,但是有效防止了left
和right
太大直接相加导致溢出。_
寻找一个数(基本的二分查找)
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;
}
1、为什么 while 循环的条件中是 <=,而不是 <?
答:因为初始化right
的赋值是nums.length - 1
,即最后一个元素的索引,而不是nums.length
。
这二者可能出现在不同功能的二分查找中,区别是:前者相当于两端都闭区间[left, right]
,后者相当于左闭右开区间[left, right)
,因为索引大小为nums.length
是越界的。
我们这个算法中使用的是前者[left, right]
两端都闭的区间。这个区间其实就是每次进行搜索的区间。
// 公众号 labuladong 看细节 ,因为我会 哈哈哈
通过本文,你学会了:
1、分析二分查找代码时,不要出现 else,全部展开成 else if 方便理解。
2、注意「搜索区间」和 while 的终止条件,如果存在漏掉的元素,记得在最后检查。
3、如需定义左闭右开的「搜索区间」搜索左右边界,只要在nums[mid] == target
时做修改即可,搜索右侧时需要减一。
4、如果将「搜索区间」全都统一成两端都闭,好记,只要稍改nums[mid] == target
条件处的代码和返回的逻辑即可,推荐拿小本本记下,作为二分搜索模板。
现在可以去把我做的诗多读几遍,体会体会其中的味道,加深理解,哈哈哈!