c++二分
C++ 二分查找完整教程:零基础看懂、直接套用的万能模板(刷题必备)
二分查找是算法入门最重要、性价比最高的算法。 只需要满足一个条件:数组有序,就能把时间复杂度从 O(n) 优化到 O(logn)。 面试、笔试、LeetCode 刷题必考。
今天这篇文章,我不讲废话,只讲:核心思想 + 两套万能模板 + 边界详解 + 常见坑,看完直接刷题。
一、二分查找核心思想
一句话总结:每次排除一半不可能的区间,快速缩小范围。
有序数组中,不需要逐个遍历,只需要对比中间元素,就能判断答案在左边还是右边。
-
中间值 小于 目标:答案一定在右边
-
中间值 大于 目标:答案一定在左边
-
中间值 等于 目标:找到答案
二、最稳的二分区间规则(必看)
新手 90% 的 bug 都是区间边界混乱导致的。 本文统一使用最稳妥、最好理解的:闭区间 [left, right]
-
left = 0
-
right = 数组长度 - 1
-
循环条件:left <= right
三、模板一:基础二分(精准查找)
适用场景:无重复数组,查找某个数是否存在
找到返回下标,找不到返回 -1
#include <iostream>
#include <vector>
using namespace std;
// 基础二分查找
int binarySearch(vector<int>& nums, int target)
{
int left = 0;
int right = nums.size() - 1;
while (left <= right)
{
// 防溢出写法,不写 (left+right)/2
int mid = left + (right - left) / 2;
if (nums[mid] == target)
{
return mid; // 找到直接返回
}
else if (nums[mid] < target)
{
left = mid + 1; // 目标在右区间
}
else
{
right = mid - 1; // 目标在左区间
}
}
return -1; // 没找到
}
int main()
{
vector<int> arr = {1,3,5,7,9,11,13};
cout << binarySearch(arr,7) << endl; // 输出 3
cout << binarySearch(arr,6) << endl; // 输出 -1
return 0;
}
重点解释
-
mid = left + (right-left)/2防止(left+right)溢出 -
为什么
mid±1?mid 已经判断过,一定可以排除 -
left <= right保证区间内所有数都被检查
四、模板二:处理重复数(找左右边界)
真实刷题大部分数组有重复元素。 比如:[1,2,2,2,3],我们经常需要找:
-
第一个 2(左边界)
-
最后一个 2(右边界)
1. 寻找左边界(第一个等于 target 的位置)
int findLeftBound(vector<int>& nums, int target)
{
int left = 0;
int right = nums.size() - 1;
int res = -1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (nums[mid] == target)
{
res = mid; // 先记录答案
right = mid - 1;// 继续往左找更靠前的
}
else if (nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return res;
}
2. 寻找右边界(最后一个等于 target 的位置)
int findRightBound(vector<int>& nums, int target)
{
int left = 0;
int right = nums.size() - 1;
int res = -1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (nums[mid] == target)
{
res = mid; // 先记录答案
left = mid + 1; // 继续往右找更靠后的
}
else if (nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return res;
}
五、C++ STL 自带二分函数(工作/比赛偷懒神器)
不需要自己手写,直接调用库函数!
#include <algorithm>
// 1. 是否存在
binary_search(nums.begin(),nums.end(),target);
// 2. 第一个 >= target 的位置(左边界)
lower_bound(nums.begin(),nums.end(),target);
// 3. 第一个 > target 的位置
upper_bound(nums.begin(),nums.end(),target);
六、新手最常见 3 个坑(一次性避坑)
坑1:数组无序也想用二分
二分的前提一定是有序,无序数组二分结果完全随机。
坑2:写死 mid = (left+right)/2
数据量大时会 int 溢出,必须使用: mid = left + (right-left)/2
坑3:找到 target 直接停止,无法处理重复数
有重复元素时,找到不能立刻 return,要继续收缩区间找边界。
七、博客总结(背诵版)
-
二分核心:有序、折半、缩区间
-
基础查找:找到即返回,mid±1 缩区间
-
边界查找:找到不返回,继续向一侧收缩
-
永远使用
left+(right-left)/2防溢出 -
刷题 90% 的二分题,两套模板足以通杀
浙公网安备 33010602011771号