目录
简单来说,二分法就是将数组从正中间一分为二,通过不断缩小范围来最终锁定答案。
时间复杂度O( logn ) ,空间复杂度O( 1 ),适用于在有序数组中查找指定元素。
虽然比较令人头疼的就是分析边界问题了,一不小心就会陷入死循环TvT
但相信我,看完这篇博客,保证你次次都能做对二分~(∠・ω< )⌒★
模板例题:力扣704. 二分查找
704. 二分查找 - 力扣(LeetCode)

这道题常规的暴力解法是,使用for循环遍历整个数组,并找出目标元素。
但这种方法并未利用题目中的升序数组条件,时间复杂度也达到了O(n)。
接下来介绍二分查找的原理和使用方法。
1.二分查找万能模板
while(left < right)
{
mid = left + (right - left) / 2;
if(nums[mid] >= target) right = mid;
else left = mid + 1;
}
while(left < right)
{
mid = left + (right - left + 1) / 2;
if(nums[mid] <= target) left = mid;
else right = mid - 1;
}
以上分为两种情况讨论,差别在于 mid 的计算是否需要加1 和 区间的收缩方向。
1. while循环:
结束条件是 left < right 而不是 <= ,是因为在循环最后 left == right ,取等会陷入死循环。
2. mid 的计算:
当 left 和 right 之间的元素个数为奇数个时,+1不会影响其指向的位置,都是指向最中间元素;但当元素个数为偶数时,没有+1时的mid偏左,+1后的mid偏右。
3. if 判断:
分为两种分支,一种是>=和<,一种是 <= 和 > 。等号位置的不同会导致区间收缩的方向不同。
由于没有等号的一边会直接跳过mid,因此如果二分数组里存在一个目标元素相同的区间,
那么结束时第一种情况指向区间左边界,第二种情况指向区间右边界。
*情况一演示:

简单来说:
- 在情况一中,即使在 mid 指向元素等于 target 的情况下,right 仍然向左移动至区间最左侧。
- 在情况二中,即使在 mid 指向元素等于 target 的情况下,left 仍然向右移动至区间最右侧。
- 如果 target 无重复元素,则两种情况等价。
// 关于查找区间的首尾下标,可以尝试这一题:
*记忆方法:
需要记忆的点很少,只有 while 和 if 括号内的条件。
其余的条件需要自己现推,例如 if 的条件中包含等号(移动至mid)和不包含等号(移动至mid的上一位 / 下一位)的情况,并在出现 right = mid - 1 时,在 mid 的计算公式中 +1 就可以了。
(类似互补的思想,整体还是很好记的)
2. 代码展示
class Solution {
public:
int search(vector<int>& nums, int target)
{
int n = nums.size();
int left = 0, right = n-1;
int mid;
while(left < right)
{
mid = left + (right - left) / 2;
if(nums[mid] >= target) right = mid;
else left = mid + 1;
}
if(nums[right] == target)
return right;
return -1;
}
};
// 感谢阅读!希望你今后遇到二分题也能如鱼得水!ヾ(≧▽≦*)o

909

被折叠的 条评论
为什么被折叠?



