题目:
给你一个按照非递减顺序排列的整数数组 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
思路:
这道题目显然是用二分法来解决,但是跟普通的二分法不同的是,这里需要使用二分法来寻找边界(因为nums中可能存在同一个数出现多次的情况)。主体思路是,我们需要写两个函数,来分别寻找左边界的右边界;得到左、右边界后,可以分3种情况来讨论:
1、target的值比数组中的最大值还要大或比数组中的最小值还要小;
2、target的值在nums的范围中,但是nums中不存在target;
3、target的值在nums的范围中,存在并找到target。
代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
// 可以分为三种情况
// 1、target比nums中所有的值都要大或小
// 2、target在nums范围中,但是不存在
// 3、target在nums范围中,存在
int leftBorder = searchLeftBorder(nums, target);
int rightBorder = searchRightBorder(nums, target);
// 情况1
if(leftBorder == -2 || rightBorder == -2){
return {-1, -1};
}
// 情况3
if((rightBorder - leftBorder) >= 2){
return {leftBorder + 1, rightBorder - 1};
}
// 情况2
return {-1, -1};
}
private:
int searchLeftBorder(vector<int>& nums, int target) {
int low = 0;
int high = nums.size() - 1;
// 记录leftBorder没有被赋值的情况,也就是target比nums中所有的值都要大
int leftBorder = -2;
while(low <= high){
int mid = (low + high) / 2;
if(nums[mid] >= target){
high = mid - 1;
leftBorder = high;
}
else{
low = mid + 1;
}
}
return leftBorder;
}
int searchRightBorder(vector<int>& nums, int target) {
int low = 0;
int high = nums.size() - 1;
// 记录rightBorder没有被赋值的情况,也就是target比nums中所有的值都要小
int rightBorder = -2;
while(low <= high){
int mid = (low + high) / 2;
if(nums[mid] <= target){
low = mid + 1;
rightBorder = low;
}
else{
high = mid - 1;
}
}
return rightBorder;
}
};