地址:https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/
题目:
Given an array of integers nums
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 ( l o g n ) O(log n) O(logn).
If the target is not found in the array, return [ − 1 , − 1 ] [-1, -1] [−1,−1].
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
理解:
一直觉得二分查找坑实在是太多,查找小于的,查找大于的,查找第一个等于的,最后一个等于的。。。
这个题就是要查找第一个等于的和最后一个等于的。
实现:
二分查找mid=(l+h)/2因为截断总会得到靠左的元素。
如果在循环中要令l=mid或者h=mid,判断条件就应该是while(l<h),否则可能会一直循环下去。
对于findLeft
,h最后指向的是大于等于target的第一个元素。跳出循环的时候,l==h
,只需要判断这个元素是不是等于target即可。
对于findRight
,本来想和上面一样用对称的思路,但是由于截断,导致会陷入死循环,因此改了一下思路。
在最后一次循环内,l==h==mid
,如果这个元素小于等于target,会把l改变,否则会减小h。即这种情况下,h总会指向最后一个等于target的元素。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.empty()) return{ -1,-1 };
int l = findLeft(nums, target);
if (l == -1) {
return{ -1,-1 };
}
return{ l,findRight(nums,target) };
}
private:
int findLeft(vector<int>& nums, int target) {
int l = 0, h = nums.size()-1;
while (l < h) {
int mid = l + (h - l) / 2;
// shrink the range such that h point to the left-most num that >= target
if (nums[mid] >= target)
h = mid;
// nums[mid]<target, then l should be bigger than mid, let l=mid+1
else
l = mid + 1;
}
// since h point to the left-most num that >= target, finally l=h.
// if nums[l]==target,return the index, otherwise, return -1
return nums[l]==target?l:-1;
}
int findRight(vector<int>& nums, int target) {
int l = 0, h = nums.size() - 1;
while (l <= h) {
int mid = l + (h - l) / 2;
if (nums[mid] <= target)
l = mid + 1;
else
h = mid - 1;
}
return nums[h] == target ? h : -1;
}
};
更一下:
关于截断导致不能用对称的方法做的,解决方法的确是在计算mid的时候手动加1从而指向靠右的位置。详见Clean iterative solution with two binary searches (with explanation)