题目描述:
给你一个按照非递减顺序排列的整数数组 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
通过次数
861.8K
提交次数
2M
通过率
42.6%
思路及解法:
大体框架就是找到数组中第一个等于target的数的位置left,和第一个大于target的位置right。如果left存在就返回[left,right-1],否则返回[-1,-1]
由于数组是非递减的,我们可以用二分法求left和right。
找第一个等于target的数的位置:
先设置要寻找的区间左端点lo=0,右端点hi=numsSize-1,当lo<=hi时,做一个循环。 如果说左端点等于target,那么left就等于lo,即if(nums[lo]==target) return lo;如果左端点就大于target或者是右端点小于target,则说明不存在left,就返回-1;取中点mid=(lo+hi)/2,如果说nums[mid]>=target,说明left在左半部分,hi=mid,否则target就在右半部分,lo=mid+1。
int binarysearch1(int *nums,int numsSize,int target)
{//第一个等于target的位置
int lo=0,hi=numsSize-1;
int ans=-1;
int mid;
while(lo<=hi)
{
if(nums[lo]==target) return lo;
//target不在区间里
if(nums[lo]>target||nums[hi]<target)
{
break;
}
mid=(lo+hi)/2;
if(target<=nums[mid])
{
hi=mid;
}
else
{
lo=mid+1;
}
}
return ans;
}
找到第一个大于target的数的位置right:
这里的方法和找left的方法差不多,也是先设置要寻找的区间左端点lo=0,右端点hi=numsSize-1,当lo<=hi时,做一个循环。在循环里,如果nums[hi]<=target,则表明数组里没有大于target的数字,那直接返回numsSize;如果说nums[lo]大于target,则表明第一个数就大于target,返回lo;取区间中点mid=(lo+hi)/2,如果说nums[mid]<=target,则说明第一个大于target的数在区间右半部分,所以lo=mid+1;否则说明right在区间左半部分,hi=mid。
int binarysearch2(int *nums,int numsSize,int target)
{//第一个大于target的位置
int ans=numsSize;
int lo=0,hi=numsSize-1;
int mid;
while(lo<=hi)
{
mid=(lo+hi)/2;
if(nums[lo]>target) return lo;
//区间内所有数都小于等于target
if(nums[hi]<=target)
{
return ans;
}
if(nums[mid]<=target)
{
lo=mid+1;
}
else
{
hi=mid;
}
}
return ans;
}
细心的朋友会发现上面两个函数很像,可以优化合并成一个函数,增加代码复用率,这个交给你们吧(其实是我不会)。
代码:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int binarysearch1(int *nums,int numsSize,int target)
{//第一个等于target的位置
int lo=0,hi=numsSize-1;
int ans=-1;
int mid;
while(lo<=hi)
{
if(nums[lo]==target) return lo;
//target不在区间里
if(nums[lo]>target||nums[hi]<target)
{
break;
}
mid=(lo+hi)/2;
if(target<=nums[mid])
{
hi=mid;
}
else
{
lo=mid+1;
}
}
return ans;
}
int binarysearch2(int *nums,int numsSize,int target)
{//第一个大于target的位置
int ans=numsSize;
int lo=0,hi=numsSize-1;
int mid;
while(lo<=hi)
{
mid=(lo+hi)/2;
if(nums[lo]>target) return lo;
//区间内所有数都小于等于target
if(nums[hi]<=target)
{
return ans;
}
if(nums[mid]<=target)
{
lo=mid+1;
}
else
{
hi=mid;
}
}
return ans;
}
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
int left=binarysearch1(nums,numsSize,target);
int right=binarysearch2(nums,numsSize,target);
int *ans=(int *)malloc(2*sizeof(int));
(*returnSize)=2;
if(left==-1)
{
ans[0]=ans[1]=-1;
}
else
{
ans[0]=left;
ans[1]=right-1;
}
return ans;
}