🧑‍🏫 阿易老师 出品

二分查找 · 学折半

为什么要二分 | 二分查找 | 大于 t 的最小值 | 小于 t 的最大值——每一步都看得见,左半还是右半?

🤔 为什么要用二分?

因为!一个数一个数地找(顺序查找)要 O(n),二分查找只要 O(logn)。数据越大,二分越划算——10 亿个数据,顺序找最多要 10 亿次,二分最多 30 次

复杂度对比 拖动滑块,感受差距
2^10 = 1,024
顺序查找 O(n)
1,024 次
二分查找 O(log n)
10 次
二分比顺序快 约 100 倍
二分查找 vs 二分答案
🔍 二分查找

找值:t 在不在数组里?在哪个位置?

比较:a[mid]t 比大小

例:在 [1,3,5,7,9] 里找 7

🆚
🎯 二分答案

找解:哪个答案能满足条件?

判断:check(mid) 行不行

例:答案在区间里,试哪个解满足

口诀:找值用比较,找解用 check!
🔍 二分查找:在有序数组里找 t

每次拿 mid = (l+r)/2 位置的数和 t 比较:相等就找到a[mid] < t 就去右半(l = mid+1);否则去左半(r = mid-1)。每轮范围砍掉一半,O(logn) 搞定!

数组 橙色 = 正在比较,绿色 = 找到,灰 = 已排除
搜索范围 mid 中间值 找到 t 已排除
控制台
速度
binary_search.cppC++
📐 二分答案:找第一个"大于 t"的数

check(x) 问:x 是不是 不够大(x ≤ t)?不够大就 l = mid+1 往右找;够大了就 r = mid-1 往左收。循环结束,l 指向第一个大于 t 的数

数组 红色 = 大于 t 的候选答案,灰色 = 不够大
搜索范围 正在检查 大于 t 最终答案
控制台
速度
lower_bound.cppC++
📐 二分答案:找最后一个"小于 t"的数

check(x) 问:x 是不是 小于 t?是就说明答案还能更大,l = mid+1;不是就 r = mid-1 往左收。循环结束,r 指向最后一个小于 t 的数

数组 绿色 = 小于 t 的候选,灰色 = 不小于 t
搜索范围 正在检查 小于 t 最终答案
控制台
速度
upper_bound.cppC++