题目表述:
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 10^5
-10^5 <= nums[i] <= 10^5
nums 是一个非递减数组
-10^9 <= target <= 10^9
解题思路:
如果题目中不要求时间复杂度,就是一道简单题了,通过前遍历和后遍历就直接查找出数组中第一个元素和最后一个元素。
时间复杂度为O(log n),又是排序好的数组,肯定是要用到二分查找
查找第一个target通过一个二分即可找到下标。但是末尾的二分查找呢?
一、可以找到target+1的位置下标,下标再减去1就是target末位置的下标。
二、通过定义第二个二分查找left赋值给l,让第二个二分查找从第一个结束下标开始查找。
完整代码:
一、
class Solution {// lower_bound 返回最小的满足 nums[i] >= target 的 i// 如果数组为空,或者所有数都 < target,则返回 nums.size()// 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]// 闭区间写法int lower_bound(vector &nums, int target) {int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right]while (left <= right) { // 区间不为空// 循环不变量:// nums[left-1] < target// nums[right+1] >= targetint mid = left + (right - left) / 2;if (nums[mid] < target)left = mid + 1; // 范围缩小到 [mid+1, right]elseright = mid - 1; // 范围缩小到 [left, mid-1]}return left; // 或者 right+1}// 左闭右开区间写法int lower_bound2(vector &nums, int target) {int left = 0, right = nums.size(); // 左闭右开区间 [left, right)while (left < right) { // 区间不为空// 循环不变量:// nums[left-1] < target// nums[right] >= targetint mid = left + (right - left) / 2;if (nums[mid] < target)left = mid + 1; // 范围缩小到 [mid+1, right)elseright = mid; // 范围缩小到 [left, mid)}return left; // 或者 right}// 开区间写法int lower_bound3(vector &nums, int target) {int left = -1, right = nums.size(); // 开区间 (left, right)while (left + 1 < right) { // 区间不为空// 循环不变量:// nums[left] < target// nums[right] >= targetint mid = left + (right - left) / 2;if (nums[mid] < target)left = mid; // 范围缩小到 (mid, right)elseright = mid; // 范围缩小到 (left, mid)}return right; // 或者 left+1}public:vector searchRange(vector &nums, int target) {int start = lower_bound(nums, target); // 使用其中一种写法即可if (start == nums.size() || nums[start] != target)return {-1, -1};// 如果 start 存在,那么 end 必定存在int end = lower_bound(nums, target + 1) - 1;return {start, end};}
};
二、
class Solution
{
public:vector searchRange(vector &nums, int target){vector v;if (nums.empty()){return {-1, -1};}int left = 0;int right = nums.size() - 1;while (left < right){int mid = (left + right) / 2;if (nums[mid] >= target){right = mid;}if (nums[mid] < target){left = mid + 1;}}int l = left;if (nums[right] != target){return {-1, -1};}left = 0;right = nums.size() - 1;while (left < right){int mid = (left + right + 1) / 2;if (nums[mid] <= target){left = mid;}if (nums[mid] > target){right = mid - 1;}}v.push_back(l);v.push_back(right);return v;}
};