leetcode 34.在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 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]

算法思想:已知该数组是非递减顺序排列的数组,所以最直接的方法就是暴力法,for循环遍历数组,先找到target,用count计数,再继续找直到第一次出现其他数,并记录其下标,最后返回[i-count,i-1],其时间复杂度是O(n),我们也可以使用双指针法,一个指向下标0,一个指向n-1(虽然时间复杂度不是最好的,但也提供了一个新思路,熟悉了这种方法,在后面的题目中也可以用到)具体代码如下:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
           int n=nums.size();
           int low=0;
           int high=n-1;
           if(n==1&&nums[0]==target)//单独分析数组长度为1的情况
                return {0,0};
           while(low<high){//当low和high相遇时,说明已经遍历完了整个数组
               if(nums[low]!=target)
                   low++;
               if(nums[high]!=target)
                   high--;
               if(nums[low]==target&&nums[high]==target)   
                   return {low,high};
           }
           
            return {-1,-1};
    }
};

言归正传,现在题目要求的是时间复杂度为O(logn),看到这个时间复杂度,那我们应该立马想到二分法,这个题目看似和二分查找很相似,都是用二分法找到目标值,但还是有不同之处,首先我们要考虑到三种情况,情况一:target>max或者target<min,如nums={3,4,5},target=1或者target=6,则返回{-1,-1}。情况二:target存在,如nums={3,4,5},target=4,则返回{1,1}。情况三:min<target<max,但target不存在,如nums={4,4,6,7},target=5,则返回{-1,-1}。如果target存在,那我们应该找到target的左右边界,然后返回左右边界的值,具体代码如下:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int left=getLeftBorder(nums, target);
        int right=getRightBorder(nums, target);
        if(left==-2 ||right==-2)//情况一
           return {-1,-1};
        if (right - left >= 0) //情况二
           return {left, right};   

        return {-1,-1};//情况三
    }
private:
int getRightBorder(vector<int>& nums, int target){//找右边界
         int getRightBorder=-2;
         int n=nums.size();
         int low=0;
         int high=n-1;
         while(low<=high){
            int mid=low+(high-low)/2;
            if(nums[mid]>target)
                 high=mid-1;
            else{                 //因为要找右边界,所以等于或小于都要往右移
                low=mid+1;
                getRightBorder=low;
            }     
         }   
         return low-1;
}
int getLeftBorder(vector<int>& nums, int target){
          int getLeftBorder=-2;
         int n=nums.size();
         int low=0;
         int high=n-1;
         while(low<=high){
            int mid=low+(high-low)/2;
            if(nums[mid]<target)
                 low=mid+1;
            else{               //因为要找左边界,所以等于或小于都要往左移
                high=mid-1;
                getLeftBorder=high;
            }     
         }   
         return high+1;           
}
};

代码可能有点繁琐,但逻辑看起来还是不难的,有什么问题大家可以在评论区讨论哦

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值