标题
C++ 实现:有序数组中二分查找左右边界(首次/最后出现位置)
左边界:东方博宜OJ ——1894 - 二分查找左侧边界
右边界:东方博宜OJ ——1895 - 二分查找右侧边界
一、前言
在算法竞赛与日常刷题中,二分查找是非常经典且高效的查找算法,时间复杂度为 O ( log n ) O(\log n) O(logn)。本文通过两道具体题目:
- 在有序非递减数组中查找给定 x x x 第一次出现的位置(左侧边界)。
- 在有序非递减数组中查找给定 x x x 最后一次出现的位置(右侧边界)。
来讲解左右边界的二分查找技巧。
二、题目一:查找左侧边界(首次出现)
给定一个长度为 n n n 的有序非递减数组(可重复),查找值为 x x x 的元素第一次出现的位置;若不存在,则输出 -1。
输入/输出格式、示例、解题思路 同上文,不再赘述。可见 左侧边界实现。
左侧边界代码示例 {#左侧边界代码}
// 查找左侧边界(第一个 >= x)
int bin_serach_left(int a[], int left, int right, int x){
while(left <= right){
int mid = left + (right - left) / 2;
if(a[mid] >= x) right = mid - 1;
else left = mid + 1;
}
return left;
}
三、题目二:查找右侧边界(最后出现)
在同样的有序非递减数组中,查找值为 x x x 的元素最后一次出现的位置;若不存在,则输出 -1。
- 输入格式 与题目一一致。
- 示例:
解释:3 最后一次在位置 6,2 最后一次在位置 4,5 不存在。输入: 6 1 2 2 2 3 3 3 3 2 5 输出: 6 4 -1
三.1 解题思路
- 明确目标:定位目标值 x x x 在数组中最后一次出现的位置(右侧边界)。
- 二分模板调整:同样维护
l=0, r=n-1。 - 边界更新:若
a[mid] <= x,则需要往右搜寻,l = mid + 1;否则(a[mid] > x),缩右界,r = mid - 1。 - 后处理:循环结束后,
r指向最后一个满足a[r] <= x的元素位置。需判断r >= 0 && a[r] == x,否则返回 -1。
三.2 右侧边界代码示例 {#右侧边界代码}
// 查找右侧边界(最后一个 <= x)
int bin_serach_right(int a[], int left, int right, int x) {
while(left <= right){
int mid = left + (right - left) / 2;
if(a[mid] <= x) left = mid + 1;
else right = mid - 1;
}
return right;
}
三.3 代码解析
- 当
a[mid] <= x时,说明目标的最后一处可能在mid或右侧,故令l = mid + 1。 - 否则(
a[mid] > x),令r = mid - 1。 - 退出循环后,
r指向最后一个小于等于 x x x 的索引,需验证其是否等于 x x x。
四、复杂度分析
- 时间复杂度:单次二分查找 O ( log n ) O(\log n) O(logn)。
- 空间复杂度: O ( n ) O(n) O(n)。
五、总结与练习
- 左右边界差异:左侧收缩右界 (
r = mid - 1),右侧收缩左界 (l = mid + 1)。 - 后处理:左侧使用
l验证,右侧使用r验证。

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



