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%的用户

参考链接

posted @ 2020-02-28 09:11  曲径通霄  阅读(95)  评论(0编辑  收藏  举报