二分法模板(基础篇)+ 2022.8.9-每日一题(贪心)


前言

  今天,写一篇算法的blog,主要内容由两部分:
  (1)把二分法的三个基础模板和一些基本例题给过一遍;
  (2)今日的LC一题,做个记录。


提示:以下是本篇文章正文内容,下面案例可供参考

一、二分法模板(基础篇)

1.三个模板的对比及介绍

  先把对应的三个模板的代码给放置在这里,我们以具体地几道题来学习这三个模板,个人认为模板二是最通用的。说在最前面二分法解题的主要步骤为:1)预处理:将判断数组进行排序;2)二分查找:对数组的空间进行划分;3)后处理:确定答案。
此部分内容参考LC官方教程,参考链接为:https://leetcode.cn/leetbook/detail/binary-search/
  先来解读一下三个模板的代码。
  模板一:这是三个模板中代码最少的,这里需要特别记住这一行代码:mid = L + (R-L) // 2,这是为防止L与R直接计算越界的情况,例如:L=200,R=220,当存储该字节的最大值为255时,直接使用(L+R)会出现越界的情况。

//代码粘贴处
def binarySearch1(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    """
    if len(nums) == 0:
        return -1

    L,R = 0, len(nums) - 1
    while L <= R:
        mid = L + (R-L) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            L = mid + 1
        else:
            R = mid - 1

    # End Condition: left > right
    return -1

  模板二:这是我认为最常用的模板格式,相对于模板一多了后处理阶段。

def binarySearch2(nums, target):
    
    if len(nums) == 0: return -1

    L,R = 0, len(nums) - 1
    while L <= R:
        mid = L + (R-L) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            L = mid + 1
        else:
            R = mid
            
    # End Condition: left == right        
    # post-processing: 
    if L != len(nums) and nums[L] == target: return L
    return -1

  模板三:这个模板我认为最不好用了,很容易因为逻辑不正确导致死循环。

def binarySearch3(nums, target):
    
    if len(nums) == 0: return -1

    L,R = 0, len(nums) - 1
    while L+1 < R:
        mid = L + (R-L) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            L = mid
        else:
            R = mid
            
    # End Condition: left+1 == right        
    # post-processing: 
    if nums[L] == target: return L
    if nums[R] == target: return R
    return -1

  总结一下,模板二中R边界的设定与LC有一定出入,但影响不大。下面我列出几个要点说一下这三个模板的主要区别:

  • End Condition:这是最大的区别,模板一不需要访问左右边界(nums[L]与nums[R]),模板二需要访问右边界(nums[R]),模板三则访问两个边界;
  • Post-processing:模板二和模板三都需要进行后处理判断决定是否使用(nums[L]与nums[R]);
  • 主要区别就是上面两点,其实具体到while函数中也有局部不同,但这都是由于End Condition所决定的,所以需要联系起来具体分析,不能死记硬背。

2.常见例题的模板应用

2.1 模板一

分享链接:
1)69 x的平方根;2)374 猜数字大小;3)33 搜索旋转排序数组

  • 这里我们就仅说一下 69 x的平方根
  • 题意:给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分

代码如下(示例):

class Solution:
    def mySqrt(self, x: int) -> int:
        L,R,ans = 0,x,-1

        # 除法的话
        if x<2: return x
        while L <= R:
            mid = (L+R)//2
            ret = x//mid
            if ret == mid:
                return mid
                break
            elif ret > mid:
                ans = mid
                L = mid+1
            else:
                R = mid-1
        return ans

    '''
        # 乘法算题
        while L<=R:
            mid = (L+R)//2
            if mid * mid <= x:
                ans = mid
                L = mid + 1
            else:
                R = mid - 1
        return ans
    '''

  

2.2 模板二

分享链接:
1)278 第一个错误的版本;2)162 寻找峰值;3)153 寻找旋转排序数组的最小值

  • 这里我们就仅说一下162 寻找峰值
  • 题意:峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值 所在位置即可。
  • 时间复杂度为 O(log n)。

代码如下(示例):

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        L,R = 0,len(nums)-1
        while L<R:
            mid = L+(R-L)//2
            # 就使劲找呗 往上爬坡
            if nums[mid] < nums[mid+1]:
                L = mid+1
            else:
                R = mid
        return L

  

2.3 模板三

1)34 在排序数组中查到元素的第一个和最后一个的位置;2)658 找到k个最接近的元素

  • 这里我们就仅说一下162 寻找峰值
  • 题意:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。
  • 时间复杂度为 O(log n)。

代码如下(示例):

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        
        # 双指针
        n = len(nums)
        if n == 0 or target not in nums: return [-1,-1]
        low,high = 0,n-1
        while low<=high:
            if nums[low] == target: low = low
            else: low += 1
            if nums[high] == target: high = high
            else: high -= 1
            if low >= 0 and high >= 0  and nums[low] == nums[high]:
                return [low,high]
                break

        '''
        # 模板三 生搬硬套有点头疼还是 双指针好用一些
        if len(nums) < 1: return [-1,-1]
        def binarySearch(L,R,id) -> int:
            while L+1 < R:
                mid = L +(R-L)//2
                if  nums[mid] < target and id > 0:
                    L = mid
                elif nums[mid] <= target and id < 0:
                    L = mid
                else:
                    R = mid
            print(L,R)
            if id > 0 : 
                if nums[L] == target: return L
                if nums[R] == target: return R
            if id < 0:
                if nums[R] == target: return R
                if nums[L] == target: return L
            return -1

        n = len(nums)
        return [binarySearch(0,n-1,1),binarySearch(0,n-1,-1)]
        '''

  

二、2022.8.9-每日一题(贪心)

题目链接:1413. 逐步求和得到正数的最小值

  • 题意:给你一个整数数组 nums 。你可以选定任意的 正数 startValue 作为初始值。你需要从左到右遍历 nums 数组,并将 startValue 依次累加上 nums 数组中的值。请你在确保累加和始终大于等于 1 的前提下,选出一个最小的 正数 作为 startValue 。

要用贪心算法,挺赖皮的。
代码如下(示例):

class Solution:
    def minStartValue(self, nums: List[int]) -> int:
        stval,cur = 0,0
        for num in nums:
            cur = num+cur
            stval = min(stval,cur)
        return -stval+1

  

三、总结

  学习确实需要广泛地积累和总结与思考,最近看了一个科幻电影《Arrival》,虽片中有一些不好的偏见,但不可不说写这篇小说的作者思想深度非常的高,我最感兴趣的一句话分享给大家。
  Despite knowing the journey … and where it leads … . I embrace it and I welcome every moment of it.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值