从基础区间收缩到旋转数组、再到「最小化最大值」二分答案,一条路线打通二分的所有变体,让你面对任何二分题都能快速锁定写法
二分查找看起来只有几行代码,实际上有三大陷阱:区间开闭选错、边界条件差一、旋转后单调性被破坏。这条路径把二分拆成三个递进阶段:先夯实「循环不变量」的基础写法,再训练边界查找和旋转数组里的条件判断,最后升维到「二分答案」——把连续函数的单调性作为判据,在答案空间而非索引空间二分。走完之后,任何二分变体都能归入这三类框架之一。
适合:想把二分边界与二分答案吃透的人
二分的本质是「每轮把搜索区间缩小一半」,关键是想清楚两件事:①区间是左闭右闭还是左闭右开,决定 while 条件和 left/right 更新方式;②mid 满足什么条件时该往左走、往右走,保持「目标始终在区间内」这一循环不变量。本阶段用四道题把这两件事反复确认到肌肉记忆。
建立「左闭右闭」模板:while(left<=right),命中即返回,否则收缩到 mid±1。「目标在 [left,right] 内」是后续变体的共同出发点。
上一题命中即返回,这题目标不存在时返回插入位置——循环退出后 left 即第一个大于 target 的下标。理清退出后 left 的语义,是边界二分的第一步。
上一题按值收缩,这题改用 isBadVersion(mid) 做判定,right 落到最左坏版本。模板从「等值命中」变为「条件判定」,是边界二分的标准形态。
上一题判定是外部 API,这题判定是 mid*mid<=x。循环退出取 right(非 left),巩固「找最大满足值」与「找最小满足值」的退出语义差异。
排序数组被旋转后整体不再单调,但旋转点把数组切成两段各自有序——二分时先判断 mid 落在哪一段,再利用该段的单调性决定收缩方向,这是旋转系列的统一思路。边界查找(首末位置)则是把「等值命中」拆成两次独立的「找最左」和「找最右」二分。
等值命中即返回,这题拆成两次二分——一次锁最左边界,一次锁最右边界,各自定向收缩,是边界二分的完整模板。
上一题有目标做基准,这题无目标——改用 nums[mid] vs nums[right] 判断最小值在哪侧,「与端点比」替代「与目标比」,是旋转系列的关键转变。
上一题只找最小值,这题找目标:复用上题「nums[mid] vs nums[left] 判哪侧有序」,再比较目标与端点决定收缩方向,是旋转二分的完整版。
把矩阵映射为一维:mid/cols 得行、mid%cols 得列,直接套里程碑 1 的等值二分模板,无需为二维另写逻辑。
「二分答案」是二分最强大的泛化形式:不在数组索引上二分,而是在「可能的答案值」组成的连续区间上二分,每次用一个判定函数(贪心/模拟)检查当前 mid 是否可行,把可行/不可行的分界线逼近最优解。这类题的核心工作量在设计单调的判定函数,二分框架本身与里程碑 1 无异。
首次把二分从索引空间升到答案空间:k 越大越可行(单调),在 [1,max(piles)] 上二分速度 k,用贪心模拟做判定函数,二分框架复用里程碑 1 模板。
同为「最小化最大值」:判定函数从除法累加换成贪心装箱,区间换成 [max,sum(weights)],骨架与上题相同,固化「判定函数+区间选取」两步思路。
二分答案终极变体:二分 nums1 切割位 i,nums2 对应切出互补个数,四端点验证合法划分。从答案空间转为划分空间二分,骨架复用「找最大满足值」语义。