一、正向查找:找满足条件的「最小值」
1. 核心特征
答案需要满足某个判定条件; 数值越大,越容易满足该条件; 题目要求:找到满足条件的最小数值。
2. 区间收缩逻辑
关键提醒:为什么不能让 r = mid - 1? 因为 mid 本身可能就是最终答案,直接减 1 会把正确答案排除出区间。
3. 循环条件推导
答案是 l:mid = l,满足条件 → r = mid = l,区间缩为 [l, l]。 答案是 r:mid = l,不满足条件 → l = mid + 1 = r,区间缩为 [r, r]。
循环执行条件:l < r 循环终止条件:l == r(此时 l/r 就是答案)
4. 正向查找代码模板
// 正向查找:数值越大越易满足条件,找满足条件的最小值boolcheck(int mid) {// 自定义:判断 mid 是否满足题目条件}intfindMinValid() {int l = 初始左边界, r = 初始右边界;while (l < r) {int mid = (l + r) / 2; // 下取整if (!check(mid)) l = mid + 1;else r = mid;}// 验证是否有满足条件的值return check(l) ? l : -1;}
二、反向查找:找满足条件的「最大值」
1. 核心特征
答案需要满足某个判定条件; 数值越小,越容易满足该条件; 题目要求:找到满足条件的最大数值。
2. 初始逻辑踩坑
mid 不满足 → 排除右侧,r = mid - 1 mid 满足 → 排除左侧,l = mid
答案是 l:mid = l,满足 → l 不变,死循环 答案是 r:mid = l,不满足 → r = l-1,区间错乱
3. 问题本质与修正
intmid=(l+r+1)/2;
4. 修正后临界验证(区间只剩 2 个值:r = l + 1)
答案是 l:mid = r,不满足 → r = mid - 1 = l,区间缩为 [l, l] 答案是 r:mid = r,满足 → l = mid = r,区间缩为 [r, r]
5. 反向查找代码模板
// 反向查找:数值越小越易满足条件,找满足条件的最大值boolcheck(int mid) {// 自定义:判断 mid 是否满足题目条件}intfindMaxValid() {int l = 初始左边界, r = 初始右边界;while (l < r) {int mid = (l + r + 1) / 2; // 上取整,关键修正if (!check(mid)) r = mid - 1;else l = mid;}// 验证是否有满足条件的值return check(l) ? l : -1;}
三、核心总结:二分查找的「对称美」
记忆口诀
找最小:mid 下取整,不满足 l=mid+1,满足 r=mid 找最大:mid 上取整,不满足 r=mid-1,满足 l=mid 循环统一:l < r,最终 l=r 即答案,记得验证
避坑关键
四、完整模板
#include<bits/stdc++.h>using namespace std;// 自定义判定函数(根据题目修改)boolcheck(int mid){return true;}// 正向查找:找满足条件的最小值intbinarySearchForward(int l, int r){while (l < r) {int mid = (l + r) / 2;if (!check(mid)) l = mid + 1;else r = mid;}return check(l) ? l : -1;}// 反向查找:找满足条件的最大值intbinarySearchBackward(int l, int r){while (l < r) {int mid = (l + r + 1) / 2;if (!check(mid)) r = mid - 1;else l = mid;}return check(l) ? l : -1;}intmain(){int l = 0, r = 100;int minValid = binarySearchForward(l, r);int maxValid = binarySearchBackward(l, r);cout << "满足条件的最小值:" << minValid << endl;cout << "满足条件的最大值:" << maxValid << endl;return 0;}
夜雨聆风