Leetcode 34. Find First and Last Position of Element in Sorted Array (python+cpp)

Leetcode 34. Find First and Last Position of Element in Sorted Array

题目

在这里插入图片描述

解法:二分查找

思路非常简单:

  • 二分法定位到一个和target相等的位置
  • 因为是排好序的,所以从这个位置开始类似双指针的向外寻找lower bound和upper bound

python代码如下:

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if len(nums) == 0:
            return [-1,-1]
        
        l = 0
        r = len(nums)-1
        if nums[l]<=target and nums[r]>=target:
            while l<=r:
                mid = l+(r-l)//2
                if nums[mid]==target:
                    l = r = mid
                    while l-1>=0 and nums[l-1]==target:
                        l-=1
                    while r+1<len(nums) and nums[r+1]==target:
                        r+=1
                    return [l,r]
                elif nums[mid]<target:
                    l+=1
                else:
                    r-=1
        
        return [-1,-1]

但其实上面的解法复杂度是O(n),并没有体现二分查找O(log(n))的复杂度,所以这道题其实就是在考C++里面的lower_bound函数和upper_bound函数。这两个函数跟普通的二分查找区别很小,只是普通的二分查找在找到元素之后就会立即返回,而lower_cound在找到target之后,不会立即返回,而是缩小「搜索区间」的上界 right,在区间 [left, mid) 中继续搜索,即不断向左收缩,达到锁定左侧边界的目的。同理upper_bound就会往右收缩找上边界。
python代码如下:

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if not nums or nums[0]>target or nums[-1]<target:
            return [-1,-1]
        
        def left_bound(lo,hi):
            while lo<=hi:
                mid = lo + (hi-lo)//2
                if nums[mid]>=target:
                    hi = mid-1
                else:
                    lo=mid+1
            return lo
        
        def right_bound(lo,hi):
            while lo<=hi:
                mid = lo + (hi-lo)//2
                if nums[mid]>target:
                    hi = mid-1
                else:
                    lo=mid+1
            return lo
        
        l = 0
        r = len(nums)-1
        
        left_bound = left_bound(l,r)
        right_bound = right_bound(l,r)-1
        if left_bound == len(nums) or nums[left_bound]!=target:
            return [-1,-1]
        return [left_bound,right_bound]

在这边顺便讲一下二分查找的左闭右开和左闭右闭。
左闭右开:[left,right),对应初始right=len(nums), while循环条件left<right, 更新边界规则left=mid+1, right=mid,返回left或者right。(因为循环终止条件为left=right)简单记忆方法:循环条件是小于,两个right不减1(代表初始化和更新时都不减1)
高级左闭右开写法:[left,right),对应初始right=len(nums), while循环条件left+1<right, 更新边界规则left=mid, right=mid,返回left或者right。(因为循环终止条件为left=right,这样永远保证check(left)=True,check(right=False), 参考下面的解析:
在这里插入图片描述

左闭右闭:[left,right], 对应初始right=len(nums)-1, while循环条件left<=right, 更新边界规则left=mid+1, right=mid-1,返回left-1或者right (因为循环终止条件为left=right+1)简单记忆方法:循环条件是小于等于,两个right都减1(代表初始化和更新时都减1)

mid表达:mid = left + (right-left)/2. 对于mid的表达来说,就只记这一种方式就好了,另一种方式可能会访问越界。
参考链接:https://www.cnblogs.com/kyoner/p/11080078.html

C++代码如下:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if (nums.size()==0) return vector<int> {-1,-1};
        
        int l=0,r=nums.size()-1,mid;
        if (nums[l]<=target && nums[r]>=target){
            while (l<=r) {
                mid = l+(r-l)/2;
                if (nums[mid]==target){
                    l=r=mid;
                    while(l-1>=0 && nums[l-1]==target) {
                        --l;
                    }
                    while(r+1<nums.size() && nums[r+1]==target){
                        ++r;
                    }
                    return vector<int> {l,r};
                }else if(nums[mid]>target){
                    --r;
                }else{
                    ++l;
                }
            }
        }
        return vector<int> {-1,-1};
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值