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

题目:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

  • 你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
    在这里插入图片描述
    解答:
    方法一:Java
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int n=nums.length;
        int leftBorder=getLeftBorder(nums,target);
        int rightBorder=getRightBorder(nums,target);
        //case1:target在数组范围之外
        if (leftBorder==-2 || rightBorder==-2){
            return new int[]{-1,-1}; 
        }
        //case3:target在数组范围之中,且数组中存在target
        if (rightBorder-leftBorder>1){
            return new int[]{leftBorder+1,rightBorder-1};
        }
        //case2:target在数组范围之中,且数组中不存在target
        return new int[]{-1,-1};

    }

    //返回大于target的第一个数的索引
    int getRightBorder(int[] nums,int target){
        int n=nums.length;
        int left=0,right=n-1;
        int rightBorder=-2;
        while (left<=right){
            int mid=left+(right-left)/2;
            if (nums[mid]>target){
                right=mid-1;
            }else{
                //寻找右边界
                left=mid+1;
                rightBorder=left;
            }
        }
        return rightBorder;
    }
    
    //返回小于target的第一个数的索引
    int getLeftBorder(int[] nums,int target){
        int n=nums.length;
        int left=0,right=n-1;
        int leftBorder=-2;
        while (left<=right){
            int mid=left+(right-left)/2;
            if (nums[mid]<target){
                left=mid+1;
            }else{
                //寻找左边界
                right=mid-1;
                leftBorder=right;
            }
        }
        return leftBorder;
    }
}

方法二:python

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        #区间范围为:[left,right]
        idx=[-1,-1]
        n=len(nums)
        if n==0:
            return idx
        left,right=0,n-1
        
        while left<=right:
            mid=left+(right-left)//2
            print(left,right,mid)
            if nums[mid]==target:
                break
            elif nums[mid]>target:
                right=mid-1
            else:
                left=mid+1
        if left>right:
            return idx
        tmp=mid  
        while tmp>=0 and nums[tmp]==target:
            tmp-=1
        idx[0]=tmp+1
        tmp=mid
        while tmp<n and nums[tmp]==target:
            tmp+=1
        idx[1]=tmp-1
        return idx

普通的二分查找

class Solution:
    #返回nums中大于target的第一个数的索引
    def getRightBorder(self,nums,target):
        n=len(nums)-1
        left,right=0,n 
        rightBorder=-2
        while left<=right:
            mid=left+(right-left)//2
            if nums[mid]>target:
                right=mid-1
            else:
                left=mid+1  
                #left更新之后,有可能大于target
                rightBorder=left
        return rightBorder
    
    ##返回nums中小于target的第一个数的索引
    def getLeftBorder(self,nums,target):
        n=len(nums)-1
        left,right=0,n 
        leftBorder=-2
        while left<=right:
            mid=left+(right-left)//2
            if nums[mid]<target:
                left=mid+1
            else:
                right=mid-1
                leftBorder=right 
        return leftBorder

    def searchRange(self, nums: List[int], target: int) -> List[int]:
        res=[-1,-1]
        leftBorder=self.getLeftBorder(nums,target)
        rightBorder=self.getRightBorder(nums,target)
        #print(leftBorder,rightBorder)
        #case1:target在数组范围之外
        #leftBorder==-2:数组中所有的数都小于target
        #rightBorder==-2:数组中所有的数都大于target
        if leftBorder==-2 or rightBorder==-2:
            return res
        #case3:target在数组范围之中,且数组中存在target
        elif rightBorder-leftBorder>1:
            return [leftBorder+1,rightBorder-1]
        #case2:target在数组范围之中,且数组中不存在target
        return res

红蓝数组(推荐)
思路:
(1)可能的情况:

  • case1: 数组中存在target ,此时返回[target的起始索引,target的终止索引]
  • case2: 数组中不存在target,此时返回[-1,-1]

(2)用到的函数:

  • getLeftBorder(nums,target):返回nums中不小于target的第一个索引值
  • getRightBorder(nums, target):返回nums中不大于target的最后一个索引值

(3)方案:

  • step1:先使用getLeftBorder()和getRightBorder()分别获得左右边界lb,rb,并将其值返回
  • step2:根据step1得到的边界值进行判断
    如果lb<=rb,则说明数组中存在target(属于case1)
    如果lb>rb,则说明数组中不存在target(属于case2)

case2特例说明:

    如果lb=0,rb=-1,则说明数组中的值都大于target,即即target处于数组范围之外

	如果lb=n,rb=n-1,则说明数组中的值都小于target,即target处于数组范围之外
class Solution:
    #返回nums中<=target的最后一个数的索引
    def getRightBorder(self,nums, target):
        l,r=-1,len(nums)
        while l+1!=r:
            m=l+(r-l)//2
            if nums[m]<=target:
                l=m
            else:
                r=m 
        return l
        
    #返回nums中>=target的第一个数的索引
    def getLeftBorder(self,nums,target):
        l,r=-1,len(nums)
        while l+1!=r:
            m=l+(r-l)//2
            if nums[m]<target:
                l=m
            else:
                r=m 
        return r

    def searchRange(self, nums: List[int], target: int) -> List[int]:
        res=[-1,-1]
        leftBorder=self.getLeftBorder(nums,target)
        rightBorder=self.getRightBorder(nums,target)
        print(leftBorder,rightBorder)
        #case1:数组中存在target
        if rightBorder>=leftBorder:
            return [leftBorder,rightBorder]
        #case2:数组中不存在target
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值