引言
当问题的解具有二段性时,二分查找是高效的解决方案。核心思路是根据待查找区间的中点位置,分析答案会出现在哪一侧,随后舍弃一半区间,在剩余部分继续查找。
对于有序数组,STL 提供了便捷的辅助函数:
lower_bound:返回大于等于目标值的最小元素的迭代器。upper_bound:返回大于目标值的最小元素的迭代器。
两者时间复杂度均为 O(log N)。理解其底层逻辑有助于处理更复杂的边界问题。
案例一:查找元素的第一个和最后一个位置
题目描述
给定一个按照升序排列的整数数组 nums 和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值,返回 [-1, -1]。
实现思路
我们需要分别找到左边界和右边界。这里有两个关键点需要注意:
- 防止死循环:当区间缩小到只剩两个元素时,取整方式决定了收敛方向。
- 合法性校验:二分结束后必须验证找到的位置是否真的等于目标值。
寻找左边界
使用标准的向下取整 (left + right) / 2。如果中间值大于等于目标值,说明目标可能在左侧或就是当前位置,将右指针移至 mid;否则左指针移至 mid + 1。
寻找右边界
为了避免死循环,需要向上取整 (left + right + 1) / 2。如果中间值小于等于目标值,说明目标可能在右侧或就是当前位置,将左指针移至 mid;否则右指针移至 mid - 1。
代码实现
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.empty()) return {-1, -1};
// 二分查找左端点
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] >= target)
right = mid;
else
left = mid + 1;
}
(nums[left] != target) {, };
retLeft = left;
left = ; right = nums.() - ;
(left < right) {
mid = (left + right + ) / ;
(nums[mid] <= target)
left = mid;
right = mid - ;
}
{retLeft, right};
}
};


