这就是二分查找啊

不多解释,按照我写了一个套路,助你随心所欲运用二分搜索一文中的模板套路,我们看一下python版本:

普通的二分查找:

def binary_search(nums, target):
    left, right = 0, len(nums)-1
    # 搜索区间[left,right]
    while left <= right:
        mid = left + (right - left) //2
        if nums[mid] == target:
            # 直接返回
            return mid
        elif nums[mid] < target:
            left = mid + 1
        elif nums[mid] > target:
            right = mid - 1
    return -1

搜索左边界:

def left_bound(nums, target):
    left, right = 0, len(nums)-1
    while left <= right:
        mid = left + (right-left)//2
        if nums[mid] == target:
            #不返回,锁定左侧边界
            right = mid -1
        elif nums[mid] < target:
            left = mid + 1
        elif nums[mid] > target:
            right = mid - 1
            
    if left >=len(nums) or nums[left] != target:
        return -1
    # 返回左侧边界
    return left

搜索右边界,拿上面的代码稍微按规律变一下就可以:

def right_bound(nums, target):
    left, right = 0, len(nums)-1
    while left <= right:
        mid = left + (right-left)//2
        if nums[mid] == target:
            #不返回,锁定右侧边界
            left = mid + 1
        elif nums[mid] < target:
            left = mid + 1
        elif nums[mid] > target:
            right = mid - 1
            
    if left < 0 or nums[right] != target:
        return -1
    # 返回左侧边界
    return right 

拿这个模板就能直接用了吗,并不能,我们还需要做很多的变换,还需要从具体的问题中抽象出模型出来:

在上文中,我们知道了我们需要找到一个单调函数f(x),以及对应的自变量x,还有那个target,针对不同的问题我们抽象出不同的[f(x),x,target],再根据题目要求找到初始化时搜索区间的左右边界,以及边界是开区间还是闭区间、确定这是不是一个搜索左右边界的问题,最后还需要确定当f(nums,mid) == target的时候,我们需要做什么,以及对应返回值应该是什么。

比如最传统的二分查找可以泛化为:

def f(nums, x):
    return nums[x]
def binary_search(nums, target):
    left, right = 0, len(nums)-1
    # 搜索区间[left,right]
    while left <= right:
        mid = left + (right - left) //2
        if f(nums, mid) == target:
            # 直接返回
            return mid
        elif f(nums, mid) < target:
            left = mid + 1
        elif f(nums, mid) > target:
            right = mid - 1
    return -1

具体的分析细节labuladong在他的文章里边已经分析的很透彻了,这里不再赘述,简单给出两道例题的python版本:

875. 爱吃香蕉的珂珂

image-20211021153842752

class Solution:
    def minEatingSpeed(self, piles: List[int], h: int) -> int:
        def f(piles,k):
            hour = 0
            for pile in piles:
                hour += pile//k
                if pile%k > 0:
                    hour += 1
            return hour
        
        left = 1
        right = 1000000000 + 1

        while left < right:
            mid = left + (right - left)//2
            if f(piles,mid) <= h:
                right = mid
            else:
                left = mid + 1
        return left
1011. 在 D 天内送达包裹的能力

image-20211021153624254

class Solution:
    def shipWithinDays(self, weights: List[int], days: int) -> int:
        def f(weights,x):
            total, days, i = 0, 0, 0
            while i < len(weights):
                if weights[i] > x-total:
                    days += 1
                    total = 0
                total += weights[i]
                i += 1
            return days+1

        left = max(weights)
        right = sum(weights) + 1
        while left < right:
            mid = left + (right -left)//2
            if f(weights,mid) <= days:
                right = mid
            else:
                left = mid + 1
        return left

需要仔细体会这种套路的精髓。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值