每日一题(LeetCode)----数组–在排序数组中查找元素的第一个和最后一个位置
1.题目(34. 在排序数组中查找元素的第一个和最后一个位置)
给你一个按照非递减顺序排列的整数数组 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.解题思路
注意:因为是非递减顺序排列,所以我们可以使用二分
一共有两种情况,按这两种情况进行处理
情况一:在数组中找不到目标值
情况二:在数组中能找到目标值
思路一:
因为是非递减顺序排列,所以我们可以使用二分
通过二分找到目标值在数组中出现的下标
如果没找到,那么返回 [-1, -1]
如果找到了,那么我们从当前位置向前遍历找到第一个不为目标值的数,那它的下一个位置就是目标值在数组中的开始位置,然后我们从当前位置向后遍历找到第一个不为目标值的数,那它的上一个位置就是目标值在数组中的结束位置
思路二(比思路一更好更快)
找目标值在数组中出现的左边界和右边界(在找左边界和右边界的过程中顺便就把目标值是否在数组中存在判断了)
1.找到右边界
我们先通过二分找到目标值
如果没找到,那么返回[-1, -1],结束
如果找到了,那么右边界进行更新,更新为当前目标值所在的位置,缩小范围,范围的左边界变为找到的目标值的右边,范围的右边界不变,继续进行查找目标值,重复操作,直到找不到目标值了,那我们就得到了目标值的右边界
2.找到左边界
我们先通过二分找到目标值
如果没找到,那么返回[-1, -1],结束
如果找到了,那么左边界进行更新,更新为当前目标值所在的位置,缩小范围,范围的右边界变为找到的目标值的左边,范围的左边界不变,继续进行查找目标值,重复操作,直到找不到目标值了,那我们就得到了目标值的左边界
3.代码
思路一的代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
vector<int> res;
res.push_back(-1);
res.push_back(-1);
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
res[0]=mid;
res[1]=mid;
break;
}
if(nums[mid]<target){
left=mid+1;
}
if(nums[mid]>target){
right=mid-1;
}
}
if(res[0]==-1||res[1]==-1){
return res;
}
int leftdata=nums[res[0]];
int leftdex=res[0];
int rightdata=nums[res[1]];
int rightdex=res[1];
while(1){
if(leftdata!=nums[leftdex]){
res[0]=leftdex+1;
break;
}
leftdex--;
if(leftdex==-1){
res[0]=0;
break;
}
}
while(1){
if(rightdata!=nums[rightdex]){
res[1]=rightdex-1;
break;
}
rightdex++;
if(rightdex==nums.size()){
res[1]=nums.size()-1;
break;
}
}
return res;
}
};
思路二(比思路一更好更快)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
vector<int> res;
res.push_back(-1);
res.push_back(-1);
//找到右边界
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
res[1]=mid;
left=mid+1;
}
if(nums[mid]<target){
left=mid+1;
}
if(nums[mid]>target){
right=mid-1;
}
}
left=0;
right=nums.size()-1;
//找到左边界
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
res[0]=mid;
right=mid-1;
}
if(nums[mid]<target){
left=mid+1;
}
if(nums[mid]>target){
right=mid-1;
}
}
return res;
}
};