题目描述
给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 $O(\log n)$ 级别。
如果数组中不存在目标值,返回 [-1, -1]
。
样例
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
算法
(两次二分) $O(\log n)$
- 第一次二分查找第一个位置使得它的值 大于等于
target
,若该位置的值不等于target
,则返回[-1, -1]
。 - 第二次二分查找第一个位置使得它的值 大于
target
。注意需要特判边界。
时间复杂度
- 两次二分时间复杂度为 $O(\log n)$。
空间复杂度
- 仅需要常数的额外空间。
C++ 代码
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int n = nums.size();
if (n == 0)
return vector<int>({-1, -1});
int l = 0, r = n - 1;
int start, end;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] < target)
l = mid + 1;
else
r = mid;
}
if (nums[l] != target)
return vector<int>({-1, -1});
start = l;
l = 0; r = n - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] <= target)
l = mid + 1;
else
r = mid;
}
if (nums[l] > target)
end = l - 1;
else
end = l;
return vector<int>({start, end});
}
};
为什么我找两次超时了
找两次次不可能会超时,可以检查下二分代码是不是有死循环
对了, 第二次binary search 的时候不用重新把l 赋值为0, 因为找last positon 从 first position 开始找就好了(从网上看来的,😁)
很好
比如以前不知道,原来算mid 的时候还有偏向左, 还是偏向右的区别, 有意识的去利用这个来缩小氛围。以前想的都是三个条件,大于,小于,等于。 如果 算mid 的时候是往左偏的,那么在更新的时候只有可能把右边界更新为mid, 否则要是把左边界更新成了mid,左右边界相邻时 新算出来的mid 还是左边界,然后mid 就一直左边界了。 同理,如果算mid 的时候是往右偏的,就不能把右边界更新为mid, 否则左右边界相邻时 新算出来的mid 还是右边界。就无法跳出循环。
特别感谢这个二分专题,对二分的理解加深了好多,谢谢谢谢!^_^
一点都不难
那是不可能的