给定一个按照升序排列的整数数组nums,和一个目标值target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值target,返回[-1, -1]。
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
思路一:双向遍历:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res{-1, -1};
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] == target)
{
res[0] = i;
res[1] = i; // 注意防止没有重复数字的情况发生
break;
}
}
for (int j = nums.size() - 1; j >= 0; j--)
{
if (nums[j] == target)
{
res[1] = j;
break;
}
}
return res;
}
};
Python版
def searchRange(self, nums: List[int], target: int) -> List[int]:
if target not in nums:
return [-1, -1]
ans = []
for i in range(len(nums)):
if nums[i] == target:
ans.append(i)
break
for i in range(len(nums)-1, -1, -1):
if nums[i] == target:
ans.append(i)
break
return ans
思路二:二分法
(1)计算下边界
此时 mid = 4 ,nums[mid] = 5,但是此时的 mid 指向的并不是第一个 5,所以我们需要继续查找 ,因为我们要找的是数的下边界,所以我们需要在 mid 的值的左区间继续寻找 5 ,那我们应该怎么做呢?我们只需在target <= nums[mid] 时,让 right = mid - 1即可,这样我们就可以继续在 mid 的左区间继续找 5 。
(2)计算上边界
计算上边界时算是和计算上边界时条件相反,
计算下边界时,当 target <= nums[mid] 时,right = mid -1;target > nums[mid] 时,left = mid + 1;
计算上边界时,当 target < nums[mid] 时,right = mid -1; target >= nums[mid] 时 left = mid + 1;刚好和计算下边界时条件相反,返回right。
class Solution {
public:
vector<int> searchRange (vector<int>& nums, int target) {
int upper = upperBound(nums,target);
int low = lowerBound(nums,target);
//不存在情况
if (upper < low) {
return {-1,-1};
}
return {low,upper};
}
//计算下边界
int lowerBound(vector<int> &nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
//这里需要注意,计算mid
int mid = left + ((right - left) >> 1);
if (target <= nums[mid]) {
//当目标值小于等于nums[mid]时,继续在左区间检索,找到第一个数
right = mid - 1;
}else if (target > nums[mid]) {
//目标值大于nums[mid]时,则在右区间继续检索,找到第一个等于目标值的数
left = mid + 1;
}
}
return left;
}
//计算上边界
int upperBound(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (target >= nums[mid]) {
left = mid + 1;
}else if (target < nums[mid]) {
right = mid - 1;
}
}
return right;
}
};