给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
要求:
(1)如果数组中不存在目标值 target,返回 [-1, -1]。
(2)你必须设计并实现时间复杂度为 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]
提示:
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array
著作权归领扣网络所有。
(1)先判断nums数组的大小,如果其中没有元素,想都不用想就返回{-1,-1}。
(2)如果有元素,通过二分法找到目标,然后以这个下标为起点往左往右遍历,直到左边或者右边的值不再是target为止。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if(nums.size() == 0){
return {-1,-1};
}else{
//二分法查找target
int left = 0;
int right = nums.size() - 1;
while(left <= right){
int middle = left + (right-left) / 2;
if(nums[middle] > target){
right = middle - 1;
}else if(nums[middle] < target){
left = middle + 1;
}else{
//如果找到了,那么left和right以middle为起点分头行动
left = middle;
right = middle;
while(left >= 0 && nums[left] == nums[middle]){
left--;
}
while(right < nums.size() && nums[right] == nums[middle]){
right++;
}
return {left+1, right-1};
}
}
}
return {-1,-1};
}
};
注意:
(1)为什么return{left+1,right-1}?
因为left–和right++总会多执行一遍,踩到了边界外面,举个例子,[2,2,2,2,3],target = 2,到最后left = -1,那么左边界值肯定是left+1 = 0。
潦草地画了一张图,大致意思就是这样。
(1)先寻找出左边界,然后寻找右边界;
(2)第一次循环遍历到最后,l肯定会和r重合,即可找到左边界
(3)同理,找右边界,注意细节即可。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> v(2,-1);//建立一个长度为2,初始值均为1的数组
int left = 0;
int right = nums.size();
//判断数组是否为空
if(nums.size()==0){
return v;
}
//先寻找左边界
while(left < right){
int middle = left + (right-left)/2;
if(nums[middle] >= target){
//如果nums[middle]==target,那么更新right的值使其向left靠拢
right = middle;//左闭右开典型特征right=middle
}else{
left = middle + 1;//左闭右开使得这里+1
}
}
//如果没有找到target,那么直接返回
if(left>nums.size()-1 || nums[left]!=target){ //这里的判断条件有注解
return v;
}
//找到了target,寻找右边界
v[0] = left;
right = nums.size();
while(left < right){
int middle = left + (right-left)/2;
if(nums[middle] <= target){
//如果nums[middle]==target,那么更新left的值使其向right靠拢
left = middle + 1;
}else{
right = middle;
}
}
v[1] = right - 1;
return v;
}
};
注意:为什么这里判断条件是left>nums.size()-1 || nums[left]!=target,因为这里面left很有可能超出边界,那么执行下面的代码就报错了。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> v(2,-1);//建立一个长度为2,初始值均为1的数组
int left = 0;
int right = nums.size() - 1;//看下面注解
//判断数组是否为空
if(nums.size()==0){
return v;
}
//先寻找左边界
while(left <= right){
int middle = left + (right-left)/2;
if(nums[middle] >= target){
//如果nums[middle]==target,那么更新right的值使其向left靠拢
right = middle - 1;//左闭右闭使得right=middle-1
}else{
left = middle + 1;//左闭右闭使得这里+1
}
}
//如果没有找到target,那么直接返回
if(left>nums.size()-1 || nums[left]!=target){
return v;
}
//找到了target,寻找右边界
v[0] = left;
right = nums.size() - 1;
while(left <= right){
int middle = left + (right-left)/2;
if(nums[middle] <= target){
//如果nums[middle]==target,那么更新left的值使其向right靠拢
left = middle + 1;
}else{
right = middle - 1;
}
}
v[1] = right;
return v;
}
};
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
vector<int> v2,v3;
int middle = 0;
while (left <= right)
{
middle = (left + right) / 2;
if (nums[middle] < target) {//在右区间
left = middle + 1;
}
else if (nums[middle] > target) {//在左区间
right = middle - 1;
}
else {//相等
v2.push_back(middle);
break;
}
}
if (v2.empty())
{
vector<int> v3(2,-1);
return v3;
}
else {
left = middle;
right = middle;
while (left - 1 >= 0 && right + 1 <= nums.size() - 1) {
if (nums[left - 1] != target && nums[right + 1] != target)
{
v2.push_back(middle);
break;
}
if (nums[left - 1] == target)
{
v2.push_back(--left);
}
if (nums[right + 1] == target)
{
v2.push_back(++right);
}
}
while (left == 0 && right + 1 <= nums.size() - 1 && nums[right + 1] == target)
{
v2.push_back(++right);
}
while (right == nums.size() - 1 && left - 1 >= 0 && nums[left - 1] == target)
{
v2.push_back(--left);
}
}
//排序
sort(v2.begin(), v2.end());
if (v2[0] == v2[v2.size() - 1])
{
v3.push_back(v2[0]);
v3.push_back(v2[0]);
}
else {
v3.push_back(v2[0]);
v3.push_back(v2[v2.size() - 1]);
}
return v3;
}
};