找排序数组特定元素的区间,意思是找开始下标和结束下标,但是题目给了要求时间复杂度低于 O(n),这就告诉我们不要使用遍历数组的方式来解题。我们查找单个元素的时候可以二分查找来完成,但是找区间的时候改用什么呢?比如:数组的排列顺序为:5 7 7 8 8 10,而 target = 8 ,我们该怎么找呢?答案还是二分查找,但是思路是这样的:我们先用二分查找找到 target 的大致位置,然后再利用该位置来查找开始下标和结束下标,意思是我们需要使用三次查找,(1)查找mid值,是nums[mid]==target ;
(2).以 left 和 mid去找开始下标;(3).以mid和right去找结束下标;说到这里应该比较明白了吧,但是我还是举个例子来说明吧:
上面的是大体上的思路,再注意到一些边界问题该题就可以解决了,代码如下:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target)
{ //
vector<int> ret;
ret.clear();
int len = nums.size();
//非正常情况
if (len == 0 || target < nums[0] || target > nums[len - 1])
{
ret.push_back(-1);
ret.push_back(-1);
return ret;
}
int left = 0;
int right = len - 1;
int mid = 0;
//简单的二分查找时不能准确的找到开始和结束点的
while (left <= right && nums[left]<=target && nums[right]>=target)
{//有一边找到了target
mid = left + (right - left) / 2;
if (nums[mid] == target)
{
break;
}
if (nums[mid] < target)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
if(nums[left]>target || nums[right]<target)
{
//不合格,最后一起处理
}
else if (left == right)
{
if (nums[left] == target)
{
ret.push_back(left);
ret.push_back(left);
return ret;
}
else
{
//没找到,到最后一起处理
}
}
else
{ // left < right ,说明nums[mid] == target,那么分别向左找开始点和向右找结束点
//左边
int lbegin = left;
int lend = mid;
int lmid = 0;
while (nums[lbegin] != target && nums[lbegin + 1] != target)
{
lmid = lbegin + (lend - lbegin) / 2;
if (nums[lmid] == target)
{//说明开始部位可能还在左边
lend = lmid;
}
else
{//nums[lmid]<target,此时说明在右边
lbegin = lmid;
}
}
//注意临界条件
if (nums[lbegin] == target)
{
ret.push_back(lbegin);
}
else
{
ret.push_back(lbegin + 1);
}
//右边
int rbegin = mid;
int rend = right;
int rmid = 0;
while (nums[rend] != target && nums[rend - 1] != target)
{
rmid = rbegin + (rend - rbegin) / 2;
if (nums[rmid] == target)
{//说明结束部位还在右边
rbegin = rmid;
}
else
{
rend = rmid;
}
}
//注意临界条件
if (nums[rend] == target)
{
ret.push_back(rend);
}
else
{
ret.push_back(rend - 1);
}
return ret;
}
//没找到
ret.push_back(-1);
ret.push_back(-1);
return ret;
}
};
结果如下: