二分查找算法原理与常见变体实战
二分查找的核心在于利用数据的有序性,通过不断缩小搜索区间来快速定位目标。虽然大家常认为它仅适用于简单的数值查找,但在实际开发中,无论是缓存索引还是参数优化,只要数据具备'二段性',二分思想都能派上用场。不过,很多开发者容易在边界处理上出错,导致死循环或越界。下面结合几个经典场景,梳理一下二分查找的实现细节。
算法原理与模板
二分的本质不是简单的折半,而是根据目标值与中间值的比较关系,排除掉一半不可能包含目标的区间。针对不同需求(如找左端点、右端点),我们需要微调 mid 的计算方式和收缩策略。
基础查找
最基础的二分查找用于判断目标是否存在。关键在于循环条件 left <= right 以及 mid 的取整方式。
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) right = mid - 1;
else left = mid + 1;
}
return -1;
寻找目标范围
当数组中存在重复元素时,我们需要找到目标值出现的起始和结束位置。这可以看作两次独立的二分查找:一次找左边界,一次找右边界。
找左边界时,如果 mid 落在目标左侧,说明目标在右边,left = mid + 1;如果 mid 落在目标或其右侧,right = mid,注意此时不能跳过 mid。

找右边界则相反,如果 mid 落在目标右侧,right = mid - 1;如果 mid 落在目标或其左侧,left = mid。为了避免死循环,mid 计算需向上取整。

class Solution {
:
{
(nums.()) {, };
left = , right = nums.() - ;
start = , end = ;
(left < right) {
mid = left + (right - left) / ;
(nums[mid] >= target) right = mid;
left = mid + ;
}
(nums[left] == target) start = left;
left = ; right = nums.() - ;
(left < right) {
mid = left + (right - left + ) / ;
(nums[mid] <= target) left = mid;
right = mid - ;
}
(nums[left] == target) end = left;
{start, end};
}
};




