1. 问题背景与核心需求
在算法竞赛和实际开发中,处理大规模数据查询是常见需求。假设你手头有一个包含10万个元素的排序数组,现在需要快速回答10万个查询——每个查询要求找出某个数值在数组中第一次出现的位置。如果直接遍历查找,时间复杂度将达到惊人的O(nq),对于大规模数据根本无法承受。
这就是我们今天要解决的经典问题:在有序不递减数组中实现高效的二分查找,准确返回目标值的首次出现位置。这个问题看似简单,但实际编码时存在诸多陷阱,需要深入理解二分查找的变体实现。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二分查找基础与问题分析
2.1 标准二分查找的局限性
标准二分查找在找到目标值后会立即返回:
cpp复制if (a[mid] == target) return mid;
但当数组存在重复元素时,这种方法会随机返回一个等于目标值的位置,无法保证是第一个。例如数组[1,2,2,2,3]中查找2,可能返回索引2、3或4中的任意一个。
2.2 左侧边界查找的核心思想
我们需要调整策略,当找到目标值时继续向左搜索:
- 当a[mid] ≥ target时,记录当前位置并收缩右边界
- 当a[mid] < target时,正常收缩左边界
- 最终第一个使a[i] ≥ target的i就是潜在解
这种思路与C++ STL中的lower_bound完全一致,是处理有序区间查找的基础算法。
3. 算法实现与优化
3.1 基础实现版本
cpp复制int binary_search_left(int a[], int n, int x) {
int left = 0, right = n - 1;
int ans = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (a[mid] >= x) {
if (a[mid] == x) ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
