一、二分查找的核心原理
二分查找仅适用于有序的数组 / 容器,核心逻辑是:
- 定义查找区间
[left, right](闭区间); - 计算区间中点
mid = left + (right - left) / 2(避免(left+right)/2导致的整数溢出); - 对比
nums[mid]与目标值target,缩小区间:- 若
nums[mid] == target:找到目标,返回索引; - 若
nums[mid] < target:目标在右半区间,更新left = mid + 1; - 若
nums[mid] > target:目标在左半区间,更新right = mid - 1;
- 若
- 当
left > right时,区间无效,说明无目标值,返回-1。
二、迭代版实现(基础版)
cpp
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; // 闭区间右边界
while (left <= right) { // 区间有效时循环
int mid = left + (right - left) / 2; // 安全计算mid
if (nums[mid] == target) {
return mid; // 找到目标,直接返回
} else if (nums[mid] < target) {
left = mid + 1; // 右半区间,排除mid
} else {
right = mid - 1; // 左半区间,排除mid
}
}
return -1; // 未找到目标
}
};
迭代版关键注意点
- 区间边界 :采用闭区间
[left, right],因此循环条件是left <= right(当left == right时,区间仍有一个元素需要检查); - mid 计算 :
left + (right - left) / 2等价于(left + right) / 2,但避免了left + right超出 int 范围的溢出问题; - 边界更新 :必须用
mid + 1/mid - 1,而非left + 1/right - 1,否则会退化为顺序查找,失去二分优势。
三、递归版实现(进阶版)
递归版将循环逻辑替换为函数自身调用,核心是 "终止条件 + 缩小区间递归"。
cpp
class Solution {
public:
// 对外接口:保持简洁,初始化递归区间
int search(vector<int>& nums, int target) {
return binarySearch(nums, target, 0, nums.size() - 1);
}
private:
// 递归辅助函数:承载核心逻辑,传递区间参数
int binarySearch(vector<int>& nums, int target, int left, int right) {
// 递归终止条件:区间无效,返回-1
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
// 递归查找右半区间
return binarySearch(nums, target, mid + 1, right);
} else {
// 递归查找左半区间
return binarySearch(nums, target, left, mid - 1);
}
}
};
递归版核心坑点(新手必看)
- 终止条件优先 :必须先判断
left > right,否则会无限递归导致栈溢出; - 返回值传递 :
- 主函数需
return递归调用的结果,否则违反函数返回值声明; - 递归分支需
return子递归的结果,否则递归结果无法层层回传(最易踩坑);
- 主函数需
- 辅助函数设计 :对外接口保持和迭代版一致,通过辅助函数传递
left/right,兼顾易用性与递归逻辑。
四、常见错误总结
- 语法错误:
nums.size忘记加括号(size()是 vector 成员函数); - 逻辑错误:边界更新用
left + 1替代mid + 1; - 递归错误:缺失
return传递递归结果; - 溢出错误:直接用
(left + right) / 2计算 mid。
五、总结
- 二分查找的核心是闭区间 + 中点对比 + 区间收缩,迭代与递归的核心逻辑完全一致;
- 迭代版注重效率,是工程实践的首选;递归版注重逻辑直观,适合理解算法本质;
- 无论哪种实现,
mid计算、边界更新、终止条件是三大核心,也是新手最易出错的点。