1. 题目
leetcode链接
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
- 0 <= nums.length <= 105
- -109 <= nums[i] <= 109
- nums 是一个非递减数组
- -109 <= target <= 109
2. 思路
三种情况:
- target不在数组范围内
- target在数组范围内,但数组中不存在target
- target在数组范围内,且数组中存在target
解题方法:
- 用二分法寻找左右边界
- 右边界:第一个大于target的下标
- 左边界:最后一个小于target的下标
- 根据左右边界处理三种情况
- 情况一:target大于数组的最大值,无右边界;target小于数组最小值,无左边界
- 情况二:当else处理
- 情况三:右边界 - 左边界 > 1
3. 代码实现
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// leftBorder、rightBorder初始化为-2
// 情况一:target不在数组范围内
if(leftBorder == -2 || rightBorder == -2) return {
-1, -1};
// 情况三:target在数组范围内,且数组中存在target
if(rightBorder - leftBorder > 1) return {
leftBorder + 1, rightBorder - 1};
// 情况二:target在数组范围内,但数组中不存在target
return {
-1, -1};
}
private:
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2;
while(left <= right){
int middle = left + (right - left) / 2;
if(nums[middle] < target){
left = middle + 1;
}else{
// 注意leftBorder是通过right得到,right记录的是大于等于target的下标
right = middle - 1;
leftBorder = right;
}
}
return leftBorder;
}
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int rightBorder = -2;
while(left <= right){
int middle = left + (right - left) / 2;
if(nums[middle] > target){
right = middle - 1;
}else{
// 注意rightBorder是通过left得到,left记录的是小于等于target的下标
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
};
4. 总结
- 左右边界的理解