34. 在排序数组中查找元素的第一个和最后一个位置
题目描述
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
输入输出
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
题解
利用两次二分
注意二分边界取值
-
第一次查找第一个>=target的位置,右边界
此时的关注点在high身上,整体靠右侧,所以mid计算时加1,同时要让high指向第一个大于等于target的位置
当左边界要更新为low=mid时,我们就令 mid =(l + r + 1)/2,上取整,此时就不会陷入死循环。
mid = (low + high + 1) / 2;//让整体靠右侧 if (nums[mid] <= target) low = mid; else high = mid - 1;
-
第二次查找最后一个<=target的位置,左边界
此时关注点在low身上
mid = (low + high) / 2; if (nums[mid] >= target) high = mid; else low = mid + 1;
代码
笨方法O(n)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(2, -1);
int low = 0;
int high = nums.size() - 1;
int mid;
int flag = 0;
while (low <= high) {
mid = (low + high) / 2;
if (nums[mid] > target)
high = mid - 1;
else if (nums[mid] < target)
low = mid + 1;
else {
flag = 1;
break;
}
}
if (!flag)
return res;
low = mid;
high = mid;
while (low >= 0 && nums[low] == target)
low--;
while (high < nums.size() && nums[high] == target)
high++;
return {low + 1, high - 1};
}
};
O(logn)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(2, -1);
if (nums.empty())
return res;
int low = 0;
int high = nums.size() - 1;
int mid;
//获得右侧边界,要让high指向大于或等于target的值
while (low < high) {
mid = (low + high + 1) / 2;//让整体靠右侧
if (nums[mid] <= target)
low = mid;
else
high = mid - 1;
}
if (nums[low] != target)
return res;
res[1] = low;
//获得左侧边界
low = 0;
//high = nums.size() - 1;
while (low < high) {
mid = (low + high) / 2;
if (nums[mid] >= target)
high = mid;
else
low = mid + 1;
};
res[0] = low;
return res;
}
};