Leetcode 34.在排序数组中查找元素的第一个和最后一个位置


题目描述:

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

进阶:你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

示例 1:

1
2
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

1
2
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

1
2
输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • $0 <= nums.length <= 10^5$
  • $-10^9 <= nums[i] <= 10^9$
  • nums 是一个非递减数组
  • $-10^9 <= target <= 10^9$

链接:

https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array


题目分析

  这个题目仍然可以使用二分查找的思路,但是由于我们要找到的是 target 值在数组中的开始位置和结束位置,则我们可以转变一下思路,变成寻找到小于 target 的最大数和大于 target 的最小数,则若还有数存在它们中间,那就是 target 了。下面给出的代码中,ansleft 表示小于 target 的最大数下标,ansright 表示大于 target 的最小数下标,这两个数允许超出数组的界限,也即可以为 -1 或者 nums.size(),这样可以应对 target 在数组边界的情况。我们先寻找 ansleft,再从 ansleft 的右边寻找 ansright,这样既缩小了搜索范围,又可以保证 ansright 大于 ansleft。注意最后返回结果之前检查一下夹在中间的值是不是 target 就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if(nums.size() == 0) return {-1, -1};

int ansleft = -1, ansright = nums.size();

int left = 0, right = nums.size()-1;
while(left <= right){
int mid = (left + right) >> 1;
if(nums[mid] >= target){
right = mid - 1;
ansleft = right;
}
else{
left = mid + 1;
}
}

left = ansleft + 1;
right = nums.size()-1;
while(left <= right){
int mid = (left + right) >> 1;
if(nums[mid] > target){
right = mid - 1;
}
else{
left = mid + 1;
ansright = left;
}
}
if(nums[ansleft+1] == target && nums[ansright-1] == target){
return {ansleft+1, ansright-1};
}
else{
return {-1, -1};
}
}
};

  时间复杂度:$O(\log n)$,其中 $n$ 是数组的大小。因为我们是采用二分查找的方法得到结果的。
  空间复杂度:$O(1)$。我们只需要常数个变量的空间。