力扣 34.在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
方法一:二分法
思路:数组时有序的,所以可以使用二分法,在区间[i,j]中找到target第一次出现的位置(左边界),和最后一次出现的位置(右边界)
左边界:由于是有序数组,从小到大,左边界需要是满足>=target的第一个数 ,mid = i+j>>1,区间二分成[i,mid] [mid+1,j]
右边界:右边界应是满足<=target的最右边一个数,mid = i+j+1>>1(防止当i = mid,j = i+1时,mid = i+j>>1 = i+i+i>>1 = mid,陷入死循环)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> ans(2, -1);
int n = nums.size();
if (n == 0) return ans;
//左边界,查找第一个>=target的位置
int i =0,j =n-1;
while(i<j){
int mid = (i+j)/2;
if(nums[mid]>=target) j = mid;
else i = mid+1;
}
if(nums[j]!=target)return ans;
ans[0] = j;
i = 0;j = n-1;
//右边界,即查找最后一个《=target的位置
while(i<j){ //[i,mid-1] [mid,j]
int mid = (i+j+1)/2;
if(nums[mid]<=target){//目标还在右边
i = mid;
}
else{//目标在左边
j = mid-1;
}
}
ans[1] = j;
return ans;
}
};
方法二:哈希表法
思路:用哈希表记录数组中数字第一次出现的下标,并将其放入哈希表,再次遇到时,更新下标,直至最后一次出现,并记录最后的下标。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
//使用哈希表存储数字第一次和最后一次出现的位置
if(nums.empty()) return res;
int p =-1;
int q =-1;
unordered_map<int,int> mp ;
for(int i =0;i<nums.size();i++){
if(nums[i]==target){
if(mp.find(target)==mp.end()){//第一次出现
mp[target] = 1;//放入,标记当前位置
p = i;
}
else{//之前出现过
q = i;
}
}
}
if(p!=-1&&q==-1){
res[0] = p;
res[1] = p;
return res;
}
res[0] = p;
res[1] = q;
return res;
}
private:
vector<int> res = {-1,-1};
};