news 2026/1/12 18:56:15

【二分查找-开区间思维】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【二分查找-开区间思维】

文章目录

  • 红蓝染色法
      • 1\. 核心逻辑:`(-1, n)`
      • 2\. 代码模板
      • 3\. 为什么很多人喜欢这种写法?(优势)
      • 4\. 劣势与注意事项
  • 开区间和闭区间的区别
      • 1\. 为什么它是“闭区间”写法?
      • 2\. 这张图在解释哪段代码?
      • 3\. 和刚才说的“双开区间”有什么区别?
      • 4\. 总结:如何看懂这张图?
  • 开区间表示的是边界的指针!里面的数是未被染色的数!
      • 1. 三个区域的定义
      • 2. 动态过程演示
      • 3. 对比:闭区间 `[L, R]` 是什么意思?
      • 总结

红蓝染色法

这种写法的核心思想是:不维护搜索区间,而是维护两个“边界指针”

1. 核心逻辑:(-1, n)

这种写法把数组想象成两种颜色(比如红色和蓝色):

  • 左指针L:始终指向“红色”区域(不满足条件的区域)。
  • 右指针R:始终指向“蓝色”区域(满足条件的区域)。
  • 目标:找到红蓝交界处。

初始化:

  • L = -1(假想数组最左侧有一个不满足条件的哨兵)
  • R = n(假想数组最右侧有一个满足条件的哨兵)
  • 这样就把所有实际元素0n-1都包在(L, R)这个开区间里了。

循环条件:

  • while L + 1 != R:(或者while L + 1 < R:
  • 解释:LR紧挨着的时候(比如L=2, R=3),说明中间没有元素了,边界找到了,循环结束。

更新逻辑:

  • 永远不需要+1-1
  • 如果mid是红色的(不满足条件):L = mid
  • 如果mid是蓝色的(满足条件):R = mid

2. 代码模板

假设我们要在一个有序数组中找到第一个 >= target的数(即 C++ 中的lower_bound):

defbinary_search_open_interval(nums,target):# 1. 初始化在数组范围之外left,right=-1,len(nums)# 2. 循环条件:当左右指针相邻时停止whileleft+1!=right:mid=left+(right-left)//2# 3. 染色判断ifnums[mid]>=target:right=mid# mid 是蓝色的(满足条件),右边界收缩到 midelse:left=mid# mid 是红色的(太小了),左边界收缩到 mid# 4. 结果处理# 循环结束时,left 指向最后一个 < target 的数# right 指向第一个 >= target 的数ifright==len(nums):return-1# 没找到,所有数都比 target 小returnright

3. 为什么很多人喜欢这种写法?(优势)

  1. 思维负担极低(无脑 mid):
    你再也不用纠结mid + 1还是mid - 1,也不用担心因为漏了+1导致死循环。因为LR总是直接赋值为mid,且循环条件保证了mid永远不会等于LR(只要R - L > 1)。

  2. 返回值清晰:

    • 如果你要找第一个满足条件的数,答案永远是R
    • 如果你要找最后一个不满足条件的数,答案永远是L
    • 不需要在return left还是return right之间犹豫。
  3. 天然处理空数组:
    如果数组是空的,left=-1,right=0,循环根本不会进入,直接返回正确结果,不需要特判。

  4. 始终不会越界:
    虽然LR初始在界外,但计算出的mid永远在[0, n-1]范围内(只要数组非空),所以nums[mid]是安全的。

4. 劣势与注意事项

  • 初始化的理解:必须要接受下标-1n这种“虚拟节点”的概念。
  • 死循环风险(微小):如果你错误地写成了while left < right且内部还是left = mid,那就会死循环。必须严格遵守while left + 1 != right

总结:我该怎么选?

  • 场景 A:单纯查找一个数(是否存在)
    👉闭区间[0, n-1]最简单直接。找到了就 return,找不到拉倒。

  • 场景 B:查找边界(第一个 >= X,最后一个 < X,最大化最小值等)
    👉双开区间(-1, n)是无敌的。
    你只需要定义好什么是“蓝”(满足条件),什么是“红”(不满足条件),最后返回RL即可。

建议:如果你觉得现在的闭区间写法处理“边界问题”经常出错(比如分不清是找左边界还是右边界),强烈建议尝试一下这个**双开区间(红蓝染色)**写法,它能统一所有复杂的二分问题。

这是一个非常棒的问题!这张图其实是在用“红蓝染色”的思想来解释“闭区间写法” (while L <= R)的原理。

简单来说:是的,这就是闭区间写法。

但是,它和我们刚才讨论的“双开区间(红蓝染色法)”在变量定义的细节上是不一样的。为了不让你晕,我来帮你拆解这张图的逻辑。


开区间和闭区间的区别

1. 为什么它是“闭区间”写法?

请看图中的两个关键细节:

  1. 最终状态是指针错位(Cross Over):
    图中R RR在左边(指向 7),L LL在右边(指向 8)。

    • 这意味着L > R L > RL>R(具体是L = R + 1 L = R + 1L=R+1)。
    • 只有闭区间的循环条件while L <= R结束时,才会出现L LL跑到R RR右边的情况。
    • 如果是双开区间(while L + 1 != R),结束时L LLR RR是紧挨着的,且L LL在左,R RR在右。
  2. 循环不变量的定义(Loop Invariant):
    图中的文字写着:

    • L − 1 L - 1L1始终是红色→ \rightarrow这意味着L指针刚刚跨过了红色区域(Red),L左边的全是红色。对应代码left = mid + 1
    • R + 1 R + 1R+1始终是蓝色→ \rightarrow这意味着R指针刚刚跨过了蓝色区域(Blue),R右边的全是蓝色。对应代码right = mid - 1

2. 这张图在解释哪段代码?

这张图对应的就是最经典的寻找左侧边界(lower_bound)的闭区间模板:

# 闭区间写法left,right=0,n-1whileleft<=right:mid=left+(right-left)//2ifnums[mid]>=target:# 遇到蓝色(满足条件)right=mid-1# 尝试往左找,R 变小,保证 R+1 及其右边全是蓝色else:# 遇到红色(太小了)left=mid+1# 必须跨过去,L 变大,保证 L-1 及其左边全是红色# 循环结束时:# right 指向红色区域的最后一个数 (图中指着 7)# left 指向蓝色区域的第一个数 (图中指着 8)returnleft

3. 和刚才说的“双开区间”有什么区别?

这是最容易混淆的地方,请注意对比:

特性闭区间 (你发的图)双开区间 (我刚才推荐的)
指针定义L,R是搜索范围的边界。L是红军代表,R是蓝军代表。
更新逻辑mid被排除 (+1-1)。mid被保留 (L=midR=mid)。
结束条件L > R(错位)L + 1 == R(相邻)
结束状态R 在左 (红),L 在右 (蓝)L 在左 (红),R 在右 (蓝)
答案return L(因为 L 最后停在蓝色起点)return R(R 本身就是蓝军代表)

4. 总结:如何看懂这张图?

这张图的作者其实是在教大家:

即使你写的是传统的while left <= right,你也可以在脑子里用“红蓝染色”来理解它。

  • 他把“答案”定义为蓝色
  • 循环结束时,left指针会停在“蓝色的第一个”
  • right指针会停在“红色的最后一个”
  • 所以图中说:R + 1是我们要找的答案(也就是L)。

结论:
如果不喜欢双开区间的-1, n写法,这张图就是你理解闭区间二分(找边界)的最佳思维模型。它完美解释了为什么最后return left而不是return right

开区间表示的是边界的指针!里面的数是未被染色的数!

双开区间(L, R)(也就是红蓝染色法)的写法中:

开区间(L, R)里面的元素,就是当前“还未被染色”(也就是还没被检查/判断)的元素区域。

我们可以把整个数组想象成三个区域:

1. 三个区域的定义

  1. [ 0 , L ] [0, L][0,L](闭区间):已知的红色区域

    • 这里面的每一个数,我们(或者初始逻辑)都已经确认过,它们是不满足条件的(或者说是“过小”的)。
    • L是红色区域的最前线哨兵。
  2. [ R , n − 1 ] [R, n-1][R,n1](闭区间):已知的蓝色区域

    • 这里面的每一个数,我们也已经确认过,它们是满足条件的(或者说是“足够大”的)。
    • R是蓝色区域的最前线哨兵。
  3. ( L , R ) (L, R)(L,R)(开区间):未知的白色/灰色区域

    • 这就是你说的“还没被判断”的区域。
    • 我们的目标就是不断缩小这个“未知区域”,直到它消失。

2. 动态过程演示

假设数组是[?, ?, ?, ?, ?],长度为 5。

初始状态:
L = -1,R = 5
此时开区间是(-1, 5)
也就是下标0, 1, 2, 3, 4全都在LR之间。
含义:“全都没检查过,全是未知区域。”

第一次二分:
mid = 2。我们检查nums[2]

  • 假设nums[2]满足条件(蓝色)。
  • 我们将R移动到mid,即R = 2
  • 含义:“哦,我看了一眼中间,发现下标 2 是蓝色的。那么 2 右边的肯定也都是蓝色的(已知)。现在的未知区域变成了(-1, 2),也就是只剩0, 1没检查了。”

循环结束条件:
while L + 1 != R
LR紧挨着(比如L=1, R=2)时,开区间(1, 2)没有整数了
含义:“未知区域为空,所有元素都已被归类为红色或蓝色。任务完成。”


3. 对比:闭区间[L, R]是什么意思?

为了加深理解,我们对比一下闭区间写法:

  • 开区间(L, R)LR是**“墙”(已确定的边界)。我们搜索的是墙中间的空间**。
  • 闭区间[L, R]LR是**“待查嫌疑人”。我们搜索的是包含LR在内的整个嫌疑人名单**。

这也是为什么:

  • 开区间里,mid检查完后,直接变成新的墙 (L=midR=mid)。
  • 闭区间里,mid检查完后,必须被剔除 (L=mid+1R=mid-1),因为它已经不是嫌疑人了。

总结

你理解得完全到位:

开区间(L, R)就是那个“待探索的未知世界”。
随着算法进行,红蓝阵营(LR)不断向中间挤压,直到把这个“未知世界”挤得一点不剩(LR相邻),二分查找就结束了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/28 7:19:07

基于大数据的小微企业信贷风险评估研究开题报告​

一、选题背景与研究意义​&#xff08;一&#xff09;选题背景​小微企业作为国民经济的重要组成部分&#xff0c;在促进就业、推动创新、稳定经济增长等方面发挥着不可替代的作用。然而&#xff0c;融资难、融资贵一直是制约小微企业发展的核心瓶颈。传统信贷风险评估模式依赖…

作者头像 李华
网站建设 2026/1/12 12:34:57

AI如何帮你快速解决.NET Framework 3.5安装问题

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个智能诊断工具&#xff0c;能够自动检测Windows系统中.NET Framework 3.5的安装状态和常见问题。工具应包含以下功能&#xff1a;1) 自动扫描系统环境&#xff1b;2) 识别常…

作者头像 李华
网站建设 2025/12/16 17:13:39

LeetCode热题100--347. 前 K 个高频元素--中等

题目 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1,2,2,3], k 2 输出&#xff1a;[1,2] 示例 2&#xff1a; 输入&#xff1a;nums [1], k 1 …

作者头像 李华