题目描述:给定一个有序数组(如[5, 7, 7, 8, 8, 10]),以及一个目标值(target=8),找出这个目标值在数组中的范围(结果是[3,4]),要求的时间复杂度为O(logN),N表示数组的长度。
1、递归解法:比较中间元素(下标为mid)与target的大小,可能出现三种情况,即中间元素等于 target,中间元素小于 target,中间元素大于 target,下面我们分情况讨论:
情况1:nums[mid]==target,则[left, right]中的left可能在序列的前半段中,right可能在序列的后半段,接下来我们可以解决原问题的两个子问题:
子问题1:在序列的前半段中找[left_1,right_1],这个left_1一定是最终的left,而right_1一定等于前面的mid;
子问题2:在序列的后半段中找[left_2,right_2],这个right_2一定是最终的right,而left_2一定等于前面的mid;
待两个子问题解决后,原问题的解就是[left_1, right_2];
情况2:nums[mid] < target,则[left,right]一定在后半段序列中,所以我们只需解决子问题2,得到的结果就是原问题的结果;
情况3:nums[mid] > target,则[left,right]一定在前半段序列中,所以我们只需解决子问题1,得到的结果就是原问题的结果;
代码如下:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res;
int size = nums.size();
int s = size, e = -1;
searchRange(nums,target,0,size-1,s,e);
if(s==size && e==-1) {
res.push_back(-1);
res.push_back(-1);
return res;
}
else{
res.push_back(s);
res.push_back(e);
return res;
}
}
void searchRange(vector<int>& nums, int &target, int low,int high,int &s,int &e){
// s代表left, e代表right
if(low>high) return ;
int mid = (low+high)/2;
if(nums[mid]==target){
searchRange(nums,target,low,mid-1,s,e);
searchRange(nums,target,mid+1,high,s,e);
s = mid<s? mid:s;
e = mid>e? mid:e;
}
else if(nums[mid]<target){
searchRange(nums,target,mid+1,high,s,e);
}
else
searchRange(nums,target,low,mid-1,s,e);
}
2、迭代解法,这个更直观一点,先找left,再找right,代码如下:
vector<int> searchRange(vector<int>& nums, int target) {
int start = 0, end = nums.size(), mid, left, right;
while (start < end) {
mid = (start + end) / 2;
if (nums[mid] >= target)
end = mid;
else
start = mid + 1;
}
left = start; // 找到了left
start = 0, end = nums.size();
while (start < end) {
mid = (start + end) / 2;
if (nums[mid] > target)
end = mid;
else
start = mid + 1;
}
right = start;// 找到了right
return left == right ? vector<int> {-1,-1} : vector<int> {left,right-1};
}