题目描述
给你一个按照非递减顺序排列的整数数组
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
分析
寻找target在数组里的左右边界,有如下三种情况:
- target在数组范围的右边或者左边,此时应该返回[-1,-1]
- target在数组范围中,且数组中不存在target,此时应该返回[-1,-1]
- target在数组范围中,且数组中存在target,此时应该返回target在数组中的开始位置和结束位置
代码实现
实现1:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 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) { // 寻找target的左边界
int left = 0;
int right = nums.size() - 1; // 左闭右闭
int leftBorder = -2; // -2表示leftBorder没有被赋值
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) {
right = middle - 1;
leftBorder = right; // 在nums[middle]==target的时候更新right,得到左边界
} else {
left = middle + 1;
}
}
return leftBorder;
}
int getRightBorder(vector<int>& nums, int target) { // 寻找target的右边界
int left = 0;
int right = nums.size() - 1; // 左闭右闭
int rightBorder = -2; // -2表示leftBorder没有被赋值
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
};
实现2:
更清晰易懂的版本
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.size() == 0){
return {-1, -1};
}
int firstPos = getFirstPos(nums, target);
// target在数组范围中,但数组中不存在target
if (firstPos == -1){
return {-1, -1};
}
int lastPos = getLastPos(nums, target);
return {firstPos, lastPos};
}
private:
int getFirstPos(vector<int>& nums, int target) { // 寻找target的开始位置
int left = 0;
int right = nums.size() - 1; // 左闭右闭
int firstPos = -1;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] == target) {
firstPos = middle;
right = middle - 1; // 向左缩小范围,找第一个等于的元素
} else if (nums[middle] > target){
//下一轮搜索区间 [left, middle - 1]
right = middle - 1;
} else {
//下一轮搜索区间 [middle + 1, right]
left = middle + 1;
}
}
return firstPos;
}
int getLastPos(vector<int>& nums, int target) { // 寻找target的结束位置
int left = 0;
int right = nums.size() - 1; // 左闭右闭
int lastPos = -1;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] == target) {
lastPos = middle;
left = middle + 1; // 向右缩小范围,找最后一个等于的元素
} else if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return lastPos;
}
};