前言
LeetCode死磕系列六:二分查找
二分查找是计算机科学中最基本、最有用的算法之一,在基础算法的学习中是非常重要的。
二分查找的最基本问题是在有序数组里查找一个特定的元素
- 二分查找算法是典型的「减治思想」的应用,我们使用二分查找将待搜索的区间逐渐缩小,以达到「缩减问题规模」的目的;
- 掌握二分查找的两种思路:
- 思路 1:在循环体内部查找元素:
while (left <= right)
;- 思路 2:在循环体内部排除元素:
while (left < right)
。- 全部使用左闭右闭区间,不建议使用左闭右开区间,反而使得问题变得复杂;
应用
1、在半有序(旋转有序或者是山脉)数组里查找元素;
2、确定一个有范围的整数;
3、需要查找的目标元素满足某个特定的性质。
模板一
- lower_bound:查找第一个大于或等于 target 的数字;
- upper_bound:查找第一个大于 target 的数字。
这一类问题的描述经常让人觉得头晕,使用模板一,就需要考虑返回 left
还是 right
。
如果使用模板二,由于退出循环以后一定有 left == right
,就只需要单独判断 left
或right
是否满足题意。
模板二
- 特征:
while (left < right)
,这里使用严格小于<
表示的临界条件是:当区间里的元素只有 2 个时,依然可以执行循环体。换句话说,退出循环的时候一定有left == right
成立,这一点在定位元素下标的时候极其有用; - 在循环体中,先考虑
nums[mid]
在满足什么条件下不是目标元素,进而考虑两个区间[left, mid - 1]
以及[mid + 1, right]
里元素的性质,目的依然是确定下一轮搜索的区间; - 根据边界情况,看取中间数的时候是否需要上取整(也就是mid 是否的计算是否需要加1)
注意事项:
- 先写分支,再决定中间数是否上取整;
- 在使用多了以后,就很容易记住,只要看到
left = mid
,它对应的取中位数的取法一定是int mid = left + (right - left + 1) / 2;
。
LeetCode 二分查找题目整理
- 704 二分查找 (基础,经典应用)
- 35 插入搜索位置
- 69 x的平方根
- 34 在排序数组中查找元素的第一个和最后一个位置(经典, 很好的模板)
题解
704. 二分查找
关于写
left = mid + 1;
还是写right = mid - 1;
上感到困惑,一个行之有效的思考策略是:永远去想下一轮目标元素应该在哪个区间里:
- 如果目标元素在区间
[left, mid - 1]
里,就需要设置设置right = mid - 1
; - 如果目标元素在区间
[mid + 1, right]
里,就需要设置设置left = mid + 1
;
- 如果目标元素在区间
考虑不仔细是初学二分法容易出错的地方,这里切忌跳步,需要仔细想清楚每一行代码的含义;
循环可以继续的条件是
while (left <= right)
,特别地,当left == right
即当待搜索区间里只有一个元素的时候,查找也必须进行下去;
35. 搜索插入位置
使用上述的模板来的话,需要考虑是返回i, 还是j 使用模板二的话,不用考虑
69. x 的平方根
34. 在排序数组中查找元素的第一个和最后一个位置
278. 第一个错误的版本
若是中间位置的版本为false, 说明第一个错误版本在[mid+1, right];