• 二分法模板(基础篇)+ 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

      总结一下,模板二中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
        '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

      

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

      

    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)]
            '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

      

    二、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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

      

    三、总结

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

  • 相关阅读:
    想找手续费低的期货公司开户不难
    数组去重复(偶然遇到这个问题,以此记录)
    基于antd实现动态修改节点的Tree组件
    grafana graphite statsd搭建安装部署 实时监控_亲测成功
    泛型知识点
    【408数据结构与算法】—直接插入排序(十五)
    Git 作用&&操作
    开发者,微服务架构到底是什么?
    C++入门基础
    51单片机的智能台灯控制系统仿真( proteus仿真+程序+原理图+报告+讲解视频)
  • 原文地址:https://blog.csdn.net/weixin_42269028/article/details/126243051