题目如下:
Given a sorted array of integers, 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].
思考分析:
基本思路和上一题目类似,以折半查找为基础。本题的特殊地方在于,返回结果不是常规的一个下标,而是一段范围。
我的代码:
// 72ms过大集合
class Solution {
public:
vector<int> _searchRange(int A[], int start, int end, int target) {
vector<int> res(2,-1);
if(end-start==-1){
return res;
}else if(end-start==0){
if(A[start]==target){
res[0]=start;
res[1]=start;
}
return res;
}else{
int mid=start+(end-start)/2;
if(target==A[mid]){
int left=mid-1;
int right=mid+1;
while(left>=start&&A[left]==target)
left--;
while(right<=end&&A[right]==target)
right++;
res[0]=left+1;
res[1]=right-1;
return res;
}else if(target>A[mid]){
return _searchRange(A, mid+1,end, target);
}else{
return _searchRange(A, start,mid-1, target);
}
}
}
vector<int> searchRange(int A[], int n, int target) {
return _searchRange(A,0,n-1,target);
}
};
小结扩展:
(1) 分析一下时间复杂度。先找到一个index,找到一个Index之后再去逐个向左扩展或者向右扩展着找范围,平均时间复杂度是O(lg n)。但是,最坏的情况下,数组的所有元素都等于target, 在这种情况下,时间复杂度是O(n)。 有没有什么办法让最坏时间复杂度也为O(lgn)呢?可以使用官网上的一个挺巧妙的做法,使用一个修改过的二分查找,先找到左边界,再找到右边界。
class Solution {
public:
vector<int> searchRange(int A[], int n, int target) {
vector<int> range(2, -1);
int lower = 0;
int upper = n;
int mid;
// Search for lower bound
while (lower < upper) {
mid = (lower + upper) / 2;
if (A[mid] < target)
lower = mid + 1;
else
upper = mid;
}
// If the target is not found, return (-1, -1)
if (A[lower] != target)
return range;
range[0] = lower;
// Search for upper bound
upper = n;
while (lower < upper) {
mid = (lower + upper) / 2;
if (A[mid] > target)
upper = mid;
else
lower = mid + 1;
}
range[1] = upper - 1;
return range;
}
};
update: 2015-01-01
class Solution {
public:
//[8,8,8,8,8,8] target = 8
vector<int> searchRange(int A[], int n, int target) {
int start = 0, end = n - 1, mid = -1;
vector<int> result;
while (start <= end) {
mid = start + (end - start) / 2;
if (A[mid] >= target) {
end = mid - 1;
} else {
start = start + 1;
}
}//根据mid的情况移动end, 最后end必然是比target小的第一个数
result.push_back(end + 1);
start = 0, end = n - 1, mid = -1;
while (start <= end) {
mid = start + (end - start) / 2;
if (A[mid] <= target) {
start = start + 1;
} else {
end = mid - 1;
}
}//根据mid的情况移动start, 最后start必然是比target大的第一个数
result.push_back(start - 1);
if (result[0] > result[1]) result = {-1, -1}; //一开始没有想到这个检验,检验当start > end时,说明找不到target
return result;
}
};
(1) http://discuss.leetcode.com/questions/213/search-for-a-range