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].
vector<int> searchRange(vector<int>& nums, int target)
{
vector<int> ret({ -1, -1 });
int N = nums.size();
if (N <= 0) return ret;
// search for the left bound
int left = 0, right = N - 1;
while (left < right)
{
// mid might == left
int mid = left + (right - left) / 2;
if (nums[mid] < target)
left = mid + 1;
else
right = mid;
}
if (nums[left] != target) return ret;
else ret[0] = left;
// search for the right bound
right = N - 1;
while (left < right)
{
// mid might == right
int mid = left + (right - left) / 2 + 1;
if (nums[mid] > target)
right = mid - 1;
else
left = mid;
}
ret[1] = right;
return ret;
}
1.二分法计算mid:mid = left + (right - left) / 2
,尽量不要使用mid = (left + right) / 2
,可能会导致溢出。
2.mid = left + (right - left) / 2
是向left偏移的:如果left
和right
中间隔着偶数个数,则mid
的位置是偏向left
一位的。
if (nums[mid] < target) left = mid + 1;
else right = mid;
所以当mid
的值大于或等于target
的时候,保持left
不动,right = mid
,因为mid
会向left
偏移,所以最终会逼近左边界。
3.计算右边界的时候:
if (nums[mid] > target) right = mid - 1;
else left = mid;
一定要保证mid
是向right
偏移的,因此mid = left + (right - left) / 2 + 1
类似的题目:
35. Search Insert Position
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. You may assume no duplicates in the array. Here are few examples. [1,3,5,6], 5 → 2 [1,3,5,6], 2 → 1 [1,3,5,6], 7 → 4 [1,3,5,6], 0 → 0
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (nums[mid] == target)
return mid;
if (nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return left;
}
其实这类题目就是考察对C++中的lower_bound和upper_bound的实现。
lower_bound是返回第一个大于或者等于val
。
template <class ForwardIterator, class T>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = distance(first, last);
while (count>0)
{
it = first; step = count / 2; advance(it, step);
if (*it<val)
{
first = ++it;
count -= step + 1;
}
else count = step;
}
return first;
}
upper_bound是返回第一个大于val
。
template <class ForwardIterator, class T>
ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = std::distance(first, last);
while (count>0)
{
it = first; step = count / 2; std::advance(it, step);
if (!(val<*it))
{
first = ++it; count -= step + 1;
}
else count = step;
}
return first;
}
another code for search for a range: 利用lower_bound
和upper_bound
.
vector<int> searchRange(vector<int>& nums, int target)
{
vector<int> res(2, -1);
int N = nums.size();
if (N <= 0) return res;
int count = N;
int first = 0;
while (count > 0)
{
int step = count / 2;
int num = nums[first + step];
if (num < target)
{
first += ++step;
count -= step;
}
else
count = step;
}
if (first >= N || nums[first] != target) return res;
else res[0] = first;
count = N - first;
while (count > 0)
{
int step = count / 2;
int num = nums[first + step];
if (!(target < num))
{
first += ++step;
count -= step;
}
else
count = step;
}
res[1] = --first;
return res;
}