leetcode 34. 在排序数组中查找元素的第一个和最后一个位置
问题描述
给定一个按照升序排列的整数数组 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]
问题分析
这里有3个注意点:
- 1.在二分法中我们使用while(left < right)而不是while(left <= right),因为这样while循环终止时一定有leftright,此时我们不必额外考虑是返回left还是right,只不过在结尾是判断这个left(right)是否符合要求就行了。
- 2.注意第二个middle值是表达式是 middle = left + (right-left+1)/2,这是一个右中值,左中值是middle = left + (right-left)/2,第二个如果不用左中值会陷入死循环,当二分法程序陷入循环时我们可以考虑换一下中值的表达式。
- 3.在分支判断的时候,我们先排除最不可能的情况赋值,其余不能得出结论的情况放在else中即可。
代码
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> ans(2,-1);
int n = nums.size();
if(n == 0 || nums[n-1] < target)return ans;
ans[0] = findfirst(nums,target);
ans[1] = findlast(nums,target);
return ans;
}
int findfirst(vector<int>& nums, int target)
{
int n = nums.size();
int left = 0,right = n-1,middle;
while(left < right)
{
middle = left + (right-left)/2;
if(nums[middle] < target){
left = middle + 1;
}
else{
right = middle;
}
}
return nums[left]==target?left:-1;
}
int findlast(vector<int>& nums, int target)
{
int n = nums.size();
int left = 0,right = n-1,middle;
while(left < right)
{
middle = left + (right-left+1)/2;
if(nums[middle] > target){
right = middle - 1;
}
else{
left = middle;
}
}
return nums[left]==target?left:-1;
}
};
结果:
执行用时 :20 ms, 在所有 C++ 提交中击败了14.12%的用户
内存消耗 :15.7 MB, 在所有 C++ 提交中击败了5.07%的用户