Medium!
题目描述:
给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]
。
示例 1:
输入: nums = [5,7,7,8,8,10]
, target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10]
, target = 6
输出: [-1,-1]
解题思路:
这道题让我们在一个有序整数数组中寻找相同目标值的起始和结束位置,而且限定了时间复杂度为O(logn),这是典型的二分查找法的时间复杂度,所以这道题也需要用此方法,我们的思路是首先对原数组使用二分查找法,找出其中一个目标值的位置,然后向两边搜索找出起始和结束的位置,代码如下:
C++解法一:
1 class Solution { 2 public: 3 vector<int> searchRange(vector<int>& nums, int target) { 4 int idx = search(nums, 0, nums.size() - 1, target); 5 if (idx == -1) return {-1, -1}; 6 int left = idx, right = idx; 7 while (left > 0 && nums[left - 1] == nums[idx]) --left; 8 while (right < nums.size() - 1 && nums[right + 1] == nums[idx]) ++right; 9 return {left, right}; 10 } 11 int search(vector<int>& nums, int left, int right, int target) { 12 if (left > right) return -1; 13 int mid = left + (right - left) / 2; 14 if (nums[mid] == target) return mid; 15 else if (nums[mid] < target) return search(nums, mid + 1, right, target); 16 else return search(nums, left, mid - 1, target); 17 } 18 };
可能有些人会觉得上面的算法不是严格意义上的O(logn)的算法,因为在最坏的情况下会变成O(n),比如当数组里的数全是目标值的话,从中间向两边找边界就会一直遍历完整个数组,那么我们下面来看一种真正意义上的O(logn)的算法,使用两次二分查找法,第一次找到左边界,第二次调用找到右边界即可。
C++解法二:
1 class Solution { 2 public: 3 vector<int> searchRange(vector<int>& nums, int target) { 4 vector<int> res(2, -1); 5 int left = 0, right = nums.size() - 1; 6 while (left < right) { 7 int mid = left + (right - left) / 2; 8 if (nums[mid] < target) left = mid + 1; 9 else right = mid; 10 } 11 if (nums[right] != target) return res; 12 res[0] = right; 13 right = nums.size(); 14 while (left < right) { 15 int mid = left + (right - left) / 2; 16 if (nums[mid] <= target) left = mid + 1; 17 else right= mid; 18 } 19 res[1] = left - 1; 20 return res; 21 } 22 };