题目要求
给你一个按照非递减顺序排列的整数数组
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
可以和二分查找一样,先将该元素查找出来,然后再将左指针和右指针都赋值为该指针的值,通过该元素的位置,判断左指针的左侧是否还继续等于该值,右指针的右侧是否还等于该值,且左指针和右指针都不可以越界,需要加上一个判断条件。
对于我之前在做二分查找类题目的时候,改变条件的时候老是将左/右指针直接变化为mid的位置上,事实上,如果当mid位置上的元素不等于target的时候,mid位置上的元素就属于一个已知状态,可以直接舍去这个位置的值,直接将left/right = mid-1/+1,这样子循环结束的条件就可以不需要很麻烦的判断,且所有可能的元素都能够在这个过程中被遍历到。
还有就是vector数组,我在下面返回的数组是临时创建了有一个数组,然后再给他赋值,其实可以直接创建一个临时数组然后返回的,比如return vector<int>{1,2,3,4(里面放应该存储的临时数组对的元素)}。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target)
{
if(nums.size()<1)
{
vector<int>a(2);
a[0] = -1;
a[1] = -1;
return a;
}
int left = 0, right = nums.size()-1, mid = (left+right)/2;
//目标有可能只有一个,那么left可能就只等于right
//如果判断条件是left<right,那么小小大的情况就判断不出来(是无限的死循环),小大大能判断出来
//但是这样判断就不知道边界点和目标值的大小了,所以应该是当找到大于和小于时,此时的mid是已知的,所以可以直接利用mid
while(left < right)
{
if(nums[mid]>target)
{
right = mid-1;
mid = (left+right)/2;
}
else if(nums[mid]<target)
{
left = mid+1;
mid = (left+right)/2;
}
else
{
break;
}
}
if(left >= right-1 && nums[mid]!=target)
{
vector<int>a(2);
a[0] = -1;
a[1] = -1;
return a;
}
left = mid;
right = mid;
// cout<<mid;
//数组有越界的风险
// while(left>=0 && nums[left--] == target);
// while(right<nums.size() && nums[right++] == target);
while(left>0 && nums[left-1] == target)
{
left--;
}
while(right < nums.size()-1 && nums[right+1] == target)
{
right++;
}
vector<int>a(2);
a[0] = left;
a[1] = right;
//或者直接返回vector<int>{left, right(里面直接放元素)}
return a;
}
};
以上代码思路仅限个人观点,如有其他想法和思路,欢迎大家一起交流进步,谢谢大家