美文网首页
死磕二分

死磕二分

作者: 霍尔元件 | 来源:发表于2019-07-17 21:57 被阅读0次

致敬经典二分

每一个细节都有它的道理:

  • left <= right 允许等于的情况
    • 因为当区间只含有一个元素时 程序可以handle
      • 这个元素等于target直接return
      • 不等于 区间收缩 可以跳出循环体
  • 循环体内对target判断的必要性
    • 提高程序效率 可能提前就找到target
    • 为了每一轮循环区间都可以得到收缩
def binarySearch(self, nums, target):
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = left + (right - left) // 2
        if nums[mid] == target:
            return mid + 1
        elif nums[mid] < target:  
            left = mid + 1
        else:
            right = mid - 1
    return -1

衍生问题

nums有重复元素,查找target,如果有多个元素,返回最左边元素的index,如果target不存在,返回target需要插入的index(插入之后nums依然有序)

基于经典二分改写

整体框架和经典二分一样,每一轮循环对重复元素左端点进行判断,有可能直接找到左端点,直接return

def bs_duplicate(self, nums, target):
    left, right = 0, len(nums) - 1
    while left <= right: # 能保证区间一直收缩,
        mid = left + (right - left) // 2
        if nums[mid] == target:
            if mid >= 1 and nums[mid - 1] == target:
                right = mid - 1
            else:
                return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return left

不一样的写法

不同于经典二分的地方:

  • while循环 条件 没有等于号
    • 当区间大小变成1的时候 避免死循环的出现
  • 不做检查 对于nums[mid] ==target的情况 采用保留mid这个index的方法
def binarySearch2(self, nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        mid = left + (right - left) // 2
        if nums[mid] < target: # target 位于右半段
            left = mid + 1
        else: # num[mid] <= target
            right = mid # 因为nums[mid] == target 是可能的 所以mid这个位置不能丢
    # return right if nums[right] == target else -1
    return right

容易出现的错误

def binarySearch__(self, nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        mid = left + (right - left) // 2
        if nums[mid] > target:
            right = mid - 1
        else:
            left = mid
    return right if nums[right] == target else -1

可以测试,上面的代码对于nums=[0,2], target=1的情况直接死循环

因为在做区间收缩之前就有left == mid,区间收缩直接失效 陷入死循环

根本原因在于mid的计算是偏向左边的,mid = (left + right) // 2, 对于case [0,2] left= mid=0, right=1

所以在写区间收缩的代码时候需要警惕left = mid的情况。

旋转数组最小值 (无重复元素)

left < right ==> mid < right 因为mid可能等于left但是绝对不可能等于right 前提是数组元素个数大于1
nums[mid] != nums[right]
所以可以比较nums[mid] 和 nums[right] 并且只有两种情况
nums[mid] > nums[right] 说明最小值在右半段 可以推出nums[mid]不可能是最小值 所以可以放心的让 left = mid + 1
nums[mid] < nums[right] 说明最小值在左半端 不能让right = mid - 1 因为mid可能是最小值 
        只能够是 right = mid 那么这样会不会使得区间不收缩 陷入死循环呢 答案是不会 因为 mid < right 区间必然收缩
当while的判断条件不再满足 left == right 找到最优解
class Solution_:
    def findMin(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        left, right = 0, len(nums) - 1
        while left < right:
            mid = (left + right) // 2
            if nums[mid] > nums[right]:
                left = mid + 1
            else:
                right = mid 
        return nums[left]

right = mid 这行代码只要数组元素个数大于1,都可以保证区间收缩

相关文章

  • 死磕二分

    致敬经典二分 每一个细节都有它的道理: left <= right 允许等于的情况因为当区间只含有一个元素时 程序...

  • “死磕”与学习

    也说“死磕” 死磕到底,死磕精神,死磕侠。互联网的发达,孕育了越来越多的网络词汇,“死磕”现在出现的频率颇高。 那...

  • 这些“死磕成本”的店,却因高体验卖出了惊人销量

    有些店死磕服务,有些死磕产品,还有些死磕成本。可有些品牌除了这些,还死磕别的... 无论何时,店铺的人工成本、租金...

  • 死磕与磕死

    前天晚上,打开百度网盘,准备听梁冬的节目睡睡平安,突然发现所有的音频转哪转哪,就是不出声音。到底哪里出了毛病?听听...

  • 磕,死磕

    疫情期间,你做的最多的是什么? 我啊~大概是反省吧,自省。 我发现反省是扇隐秘的门,一旦打开,就像探险一样,不停的...

  • 死磕别人,不如死磕自己

    【死磕别人,不如死磕自己。】有朋友是干销售的,任凭那股子死磕别人的毅力,一切都是那么不可控,最后只剩毅力。与其死磕...

  • 微信公众号运营如何让你的文章阅读量暴涨?

    对于绝大多少微信公众号运营编辑来说,每天做的基本就是死磕找文,然后死磕标题,接着死磕配图,再死磕排版,文章发出去之...

  • 每日练字-抄论语(8)

    死磕

  • 死磕

    今天学到的关键词。 死磕到底没有解决不了的事,什么英语,什么吉他,什么书法……一切都不是事儿。 我就是要死磕到底了。

  • 死磕

    好多天没写东西,果然最简单的也是最难的。

网友评论

      本文标题:死磕二分

      本文链接:https://www.haomeiwen.com/subject/xlkhlctx.html