Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].
方法一:两指针法
思路:
- 一个指针从数组头开始遍历,一旦找到目标值后就将其下标保存到输出数组中。
- 另一个指针从数组尾开始遍历,一旦找到目标值后就将其下包保存到输出数组中。
细节:
- 可以先将输出数组初始化成[-1,-1],当第一遍遍历完成后,如果数组数值仍然是[-1,-1],则说明数组中不包含目标值,也就不需要第二次遍历了,直接返回输出数组。
- 时间复杂度O(n),所以此方法不满足题目要求的时间复杂度,但官网上可以通过。
- 空间复杂度:O(1)。
C++实现
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(2,-1);
for(int i=0;i<nums.size();++i)
{
if(nums[i]==target)
{
res[0]=i;
break;
}
}
if(res[0]==-1)
return res;
for(int i=nums.size()-1;i>=0;--i)
{
if(nums[i]==target)
{
res[1]=i;
break;
}
}
return res;
}
};
方法二:二分查找
思路:使用改进的二分查找分别寻找区间的两个端点。
步骤:
- 首先定义两个指针分别指向数组的头与尾。
- 寻找左端点:如果数组的中间值大于或者等于目标值时,说明左端点位于数组的左边(包括中间值),所以我们就将右指针移到当前数组的中间位置,继续查找;如果数组的中间值小于目标值,说明左端点位于数组的右边,我们就将左指针移到当前数组的中间位置的下一位置上,继续查找。
- 以这种方式搜索完成后,左指针就指向了左端点。我们需要注意到一些边界情况:当左指针超过数组下标范围,或者左指针就没移动过时,我们需要对此进行判断该数组中是否存在目标值,如果没有则直接返回输出数组。
- 寻找右端点:这里有两种方法。第一种方法就是在前面搜索的基础上,再在剩下的右半段中寻找右端点,我们需要使用一个技巧,让中间端点为
mid=(lo+hi)/2+1;
,这样就不影响循环,思想和寻找左端点差不多。
另一种是只要当数组中间值不大于目标值时就将左指针指向中间的下一位,注意最后要将左指针减1,所以需要先将右指针指向数组末尾的下一位。
时间复杂度:O(log n);空间复杂度:O(1)。
Java实现
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res={-1,-1};
int lo=0,hi=nums.length-1;
//求区间左端点
while(lo<hi)
{
int mid=(lo+hi)/2;
if(nums[mid]>=target)
hi=mid;
else
lo=mid+1;
}
if(lo==nums.length||nums[lo]!=target)
return res;
res[0]=lo;
//求区间右端点
hi=nums.length-1;
while(lo<hi)
{
int mid=(lo+hi)/2+1;
if(nums[mid]>target)
hi=mid-1;
else
lo=mid;
}
res[1]=lo;
return res;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res={-1,-1};
int lo=0,hi=nums.length-1;
//求区间左端点
while(lo<hi)
{
int mid=(lo+hi)/2;
if(nums[mid]>=target)
hi=mid;
else
lo=mid+1;
}
if(lo==nums.length||nums[lo]!=target)
return res;
res[0]=lo;
//求区间右端点
lo=0;
hi=nums.length;
while(lo<hi)
{
int mid=(lo+hi)/2;
if(nums[mid]>target)
hi=mid;
else
lo=mid+1;
}
res[1]=lo-1;
return res;
}
}