网站的特点,如何免费自己做网站,学校 网站源码,python抓取更新wordpress文章目录红蓝染色法1\. 核心逻辑#xff1a;(-1, n)2\. 代码模板3\. 为什么很多人喜欢这种写法#xff1f;#xff08;优势#xff09;4\. 劣势与注意事项开区间和闭区间的区别1\. 为什么它是“闭区间”写法#xff1f;2\. 这张图在解释哪段代码#xff1f;3\. 和刚才说的…文章目录红蓝染色法1\. 核心逻辑(-1, n)2\. 代码模板3\. 为什么很多人喜欢这种写法优势4\. 劣势与注意事项开区间和闭区间的区别1\. 为什么它是“闭区间”写法2\. 这张图在解释哪段代码3\. 和刚才说的“双开区间”有什么区别4\. 总结如何看懂这张图开区间表示的是边界的指针里面的数是未被染色的数1. 三个区域的定义2. 动态过程演示3. 对比闭区间 [L, R] 是什么意思总结红蓝染色法这种写法的核心思想是不维护搜索区间而是维护两个“边界指针”。1. 核心逻辑(-1, n)这种写法把数组想象成两种颜色比如红色和蓝色左指针L始终指向“红色”区域不满足条件的区域。右指针R始终指向“蓝色”区域满足条件的区域。目标找到红蓝交界处。初始化L -1假想数组最左侧有一个不满足条件的哨兵R n假想数组最右侧有一个满足条件的哨兵这样就把所有实际元素0到n-1都包在(L, R)这个开区间里了。循环条件while L 1 ! R:或者while L 1 R:解释当L和R紧挨着的时候比如L2, R3说明中间没有元素了边界找到了循环结束。更新逻辑永远不需要1或-1。如果mid是红色的不满足条件L mid如果mid是蓝色的满足条件R mid2. 代码模板假设我们要在一个有序数组中找到第一个 target的数即 C 中的lower_bounddefbinary_search_open_interval(nums,target):# 1. 初始化在数组范围之外left,right-1,len(nums)# 2. 循环条件当左右指针相邻时停止whileleft1!right:midleft(right-left)//2# 3. 染色判断ifnums[mid]target:rightmid# mid 是蓝色的满足条件右边界收缩到 midelse:leftmid# mid 是红色的太小了左边界收缩到 mid# 4. 结果处理# 循环结束时left 指向最后一个 target 的数# right 指向第一个 target 的数ifrightlen(nums):return-1# 没找到所有数都比 target 小returnright3. 为什么很多人喜欢这种写法优势思维负担极低无脑 mid你再也不用纠结mid 1还是mid - 1也不用担心因为漏了1导致死循环。因为L和R总是直接赋值为mid且循环条件保证了mid永远不会等于L或R只要R - L 1。返回值清晰如果你要找第一个满足条件的数答案永远是R。如果你要找最后一个不满足条件的数答案永远是L。不需要在return left还是return right之间犹豫。天然处理空数组如果数组是空的left-1,right0循环根本不会进入直接返回正确结果不需要特判。始终不会越界虽然L和R初始在界外但计算出的mid永远在[0, n-1]范围内只要数组非空所以nums[mid]是安全的。4. 劣势与注意事项初始化的理解必须要接受下标-1和n这种“虚拟节点”的概念。死循环风险微小如果你错误地写成了while left right且内部还是left mid那就会死循环。必须严格遵守while left 1 ! right。总结我该怎么选场景 A单纯查找一个数是否存在闭区间[0, n-1]最简单直接。找到了就 return找不到拉倒。场景 B查找边界第一个 X最后一个 X最大化最小值等双开区间(-1, n)是无敌的。你只需要定义好什么是“蓝”满足条件什么是“红”不满足条件最后返回R或L即可。建议如果你觉得现在的闭区间写法处理“边界问题”经常出错比如分不清是找左边界还是右边界强烈建议尝试一下这个**双开区间红蓝染色**写法它能统一所有复杂的二分问题。这是一个非常棒的问题这张图其实是在用“红蓝染色”的思想来解释“闭区间写法” (while L R)的原理。简单来说是的这就是闭区间写法。但是它和我们刚才讨论的“双开区间红蓝染色法”在变量定义的细节上是不一样的。为了不让你晕我来帮你拆解这张图的逻辑。开区间和闭区间的区别1. 为什么它是“闭区间”写法请看图中的两个关键细节最终状态是指针错位Cross Over图中R RR在左边指向 7L LL在右边指向 8。这意味着L R L RLR具体是L R 1 L R 1LR1。只有闭区间的循环条件while L R结束时才会出现L LL跑到R RR右边的情况。如果是双开区间(while L 1 ! R)结束时L LL和R RR是紧挨着的且L LL在左R RR在右。循环不变量的定义Loop Invariant图中的文字写着L − 1 L - 1L−1始终是红色→ \rightarrow→这意味着L指针刚刚跨过了红色区域RedL左边的全是红色。对应代码left mid 1。R 1 R 1R1始终是蓝色→ \rightarrow→这意味着R指针刚刚跨过了蓝色区域BlueR右边的全是蓝色。对应代码right mid - 1。2. 这张图在解释哪段代码这张图对应的就是最经典的寻找左侧边界lower_bound的闭区间模板# 闭区间写法left,right0,n-1whileleftright:midleft(right-left)//2ifnums[mid]target:# 遇到蓝色满足条件rightmid-1# 尝试往左找R 变小保证 R1 及其右边全是蓝色else:# 遇到红色太小了leftmid1# 必须跨过去L 变大保证 L-1 及其左边全是红色# 循环结束时# right 指向红色区域的最后一个数 (图中指着 7)# left 指向蓝色区域的第一个数 (图中指着 8)returnleft3. 和刚才说的“双开区间”有什么区别这是最容易混淆的地方请注意对比特性闭区间 (你发的图)双开区间 (我刚才推荐的)指针定义L,R是搜索范围的边界。L是红军代表R是蓝军代表。更新逻辑mid被排除 (1或-1)。mid被保留 (Lmid或Rmid)。结束条件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. 三个区域的定义[ 0 , L ] [0, L][0,L]闭区间已知的红色区域。这里面的每一个数我们或者初始逻辑都已经确认过它们是不满足条件的或者说是“过小”的。L是红色区域的最前线哨兵。[ R , n − 1 ] [R, n-1][R,n−1]闭区间已知的蓝色区域。这里面的每一个数我们也已经确认过它们是满足条件的或者说是“足够大”的。R是蓝色区域的最前线哨兵。( L , R ) (L, R)(L,R)开区间未知的白色/灰色区域。这就是你说的“还没被判断”的区域。我们的目标就是不断缩小这个“未知区域”直到它消失。2. 动态过程演示假设数组是[?, ?, ?, ?, ?]长度为 5。初始状态L -1,R 5。此时开区间是(-1, 5)。也就是下标0, 1, 2, 3, 4全都在L和R之间。含义“全都没检查过全是未知区域。”第一次二分mid 2。我们检查nums[2]。假设nums[2]满足条件蓝色。我们将R移动到mid即R 2。含义“哦我看了一眼中间发现下标 2 是蓝色的。那么 2 右边的肯定也都是蓝色的已知。现在的未知区域变成了(-1, 2)也就是只剩0, 1没检查了。”循环结束条件while L 1 ! R当L和R紧挨着比如L1, R2时开区间(1, 2)里没有整数了。含义“未知区域为空所有元素都已被归类为红色或蓝色。任务完成。”3. 对比闭区间[L, R]是什么意思为了加深理解我们对比一下闭区间写法开区间(L, R)L和R是**“墙”已确定的边界。我们搜索的是墙中间的空间**。闭区间[L, R]L和R是**“待查嫌疑人”。我们搜索的是包含L和R在内的整个嫌疑人名单**。这也是为什么开区间里mid检查完后直接变成新的墙 (Lmid或Rmid)。闭区间里mid检查完后必须被剔除 (Lmid1或Rmid-1)因为它已经不是嫌疑人了。总结你理解得完全到位开区间(L, R)就是那个“待探索的未知世界”。随着算法进行红蓝阵营L和R不断向中间挤压直到把这个“未知世界”挤得一点不剩L和R相邻二分查找就结束了。