当前位置: 首页 > news >正文

【python|二分|leetcode441】一题搞清楚二分区间问题---闭区间、左闭右开、左开右闭、全开区间

every blog every motto: Although the world is full of suffering, it is full also of the overcoming of it

0. 前言

一题搞清楚二分区间问题—闭区间、左闭右开、左开右闭、全开区间

0.1 题目:Problem: 441. 排列硬币

你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。

给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。

在这里插入图片描述


计算m行对应的硬币数,由于是等差数列, ( 首项 + 尾项) ∗ 项数 / 2 (首项+尾项)*项数/2 (首项+尾项)项数/2 ,即:
( 1 + m ) ∗ m / 2 (1+m)∗m/2 (1+m)m/2

总硬币数为n,所以我们需要比较两个的大小,即,满足

( 1 + m ) ∗ m / 2 < = n (1+m)∗m/2<=n (1+m)m/2<=n

变换后:

( 1 + m ) ∗ m < = 2 ∗ n (1+m)∗m<=2∗n (1+m)m<=2n

即通过二分法不断尝试m的可能取值。

敲重点:

while 循环条件决定是闭区间还是开区间
while 循环条件决定是闭区间还是开区间
while 循环条件决定是闭区间还是开区间


1 闭区间

闭区间,m是向上取整还是向下取整都可以,

由于是闭区间,m对应的值是可以取到的
由于是闭区间,m对应的值是可以取到的
由于是闭区间,m对应的值是可以取到的

所以,不管left 还是right的更新,都需要在m的基础上加一或是减一

举个例子:当区间为【2,2】,不满足条件时,需要更新left或right,如果此时left = m,那么就陷入了死循环;right同理。

class Solution:
    def arrangeCoins(self, n: int) -> int:
        l, r = 1, n 

        while l <= r: # 闭区间
            m = (l + r )//2 #·‌向下取整,eg:·‌(3+4)//2·‌=>·‌3
            # m = (l + r +1)//2 

            if m * (m+1) <= 2*n:
                l = m + 1
            else:
                r = m - 1
            # m = (l + r + 1)//2 # 向上取整,eg (3+4+1)//2 => 4
        
        return l - 1

2 左闭右开【)

常规的默认写法是 m = (l+r)//2,这里蕴含着向下取整在里面,所以这个对应的是左闭右开。

故,当更新时,l = m+ 1 (若,当区间为【3,4】,m = (3+4)//2 = 3,l = m = 3,区间没有变化,死循环);

而 r= m ,

class Solution:
    def arrangeCoins(self, n: int) -> int:
        l, r = 1, n 

        while l < r: 
            # 左闭右开区间 [)
            m = (l + r )//2 # 向下取整,eg: (3+4)//2 => 3
            if m * (m+1) <= 2*n:
                l = m + 1
            else:
                r = m 
        return l - 1 if n != 1 else 1

3 左开右闭(】

由于m是向上取整,取右区间对应的值,eg: 区间为[3,4],m = (3+4+1)//2 = 4,

右区间是取到的,所以当更新时:r = m - 1 (如果r = m,即r = 4,区间没有变化,死循环);

而左区间取不到,所以 l = m

class Solution:
    def arrangeCoins(self, n: int) -> int:
        l, r = 1, n 

        while l < r: 
            # 向上取整,不加1是向下取整
            # 左开右闭区间 (]
            m = (l + r +1 )//2 # 向上取整,eg (3+4+1)//2 => 4
            if m * (m+1) <= 2*n:
                l = m 
            else:
                r = m - 1
        return l 

4 全开区间

  1. 全开区间的默认条件写法是: l +1 < r
  2. 初始条件是两个不满足条件的值:l, r = 0, n + 1
  3. 由于是开区间,m,向下还是向上取整都是可以的,和闭区间类似
  4. 由于是left和right的更新 l = m 或r = m`
class Solution:
    def arrangeCoins(self, n: int) -> int:
        l, r = 0, n + 1 # 注意初始值

        while l + 1 < r: 
            # 全开区间 ()
            m = (l + r )//2
            # m = (l + r +1)//2

            if m * (m+1) <= 2*n:
                l = m
            else:
                r = m 
        return l
            # m = (l + r + 1)//2

5 总结

5.1 开区间还是闭区间,有while条件决定

* <=是闭区间
* < 开区间,具体哪种由mid的取值决定
	* m = (left + right)//2,向下取整,所以left能够取到,左闭右开 `[)`
	* m = (left + right + 1)//2, 向上取整,right能够取到,左开右闭 `(]`

5.2 left 和right的更新

* 当闭区间【】时,left = m + 1; right = m - 1
* 当全开区间()时,left = m ; right = m
* 当左闭右开【)时,left = m + 1; right = m
* 当左开右闭(】时,lefet = m; right = m - 1

5.3 m值的计算

5.3.1 闭区间

向上向下取整都可以

m = (l + r +1)//2
m = (l + r )//2

5.3.2 左闭右开【)

m = (l + r )//2 # 向下取整,eg: (3+4)//2 => 3

5.3.3 左开右闭(】

m = (l + r + 1)//2 # 向下取整,eg: (3+4+1)//2 => 4

5.3.4 全开区间()

都可以,同闭区间

m = (l + r +1)//2
m = (l + r )//2

相关文章:

  • DeepSeek引领端侧AI革命,边缘智能重构AI价值金字塔
  • PPT:仓储管理与WMS
  • 在VMware Workstation Pro上轻松部署CentOS7 Linux虚拟机
  • 数据篇| App爬虫入门(一)
  • datax-coud部署
  • Flutter中stream学习
  • PyTorch调试与错误定位技术
  • Dify Web 前端独立部署指南(与后端分离,独立部署)
  • 如何在c# 项目中使用redis
  • 前端大屏展示可视化-地图的绘制(天地图)
  • 基于springboot+vue的佳途旅行分享预约平台
  • Linux之磁盘管理
  • ThinkPHP框架中各模块通过MVC架构和扩展机制协同工作形成完整的请求处理流程
  • 三:FFMPEG拉流读取模块的讲解
  • 【力扣】2629. 复合函数——函数组合
  • macOS 如何进入安全模式
  • 阿里千问大模型(Qwen2.5-VL-7B-Instruct)部署
  • 【每日学点HarmonyOS Next知识】拖拽调整列表顺序、tab回弹、自定义弹窗this、状态变量修饰枚举
  • TypeScript接口:结构化类型的契约之道
  • 成为git砖家(9): rebase进阶: 拆分commit为多个
  • wordpress 导航菜单设置/seo网站系统
  • 北京城乡建设委员会网站共有产权房/国外独立站网站
  • 开传奇私服网站怎么做/免费域名解析
  • 做电池网站的引导页/万网域名购买
  • 1000平方办公室装修多少钱/娄底地seo
  • 北京西站地铁几号线/关键词seo排名优化推荐