← 返回内容列表

二分查找与主定理:为什么 log n 是分治的标准答案

分享本文
二分查找与主定理:为什么 log n 是分治的标准答案

二分查找 20 行代码,复杂度却是 O(log n)。把它写成递推式 T(n)=T(n/2)+1,主定理情况2 一眼给出 Θ(log n)——分治把"线性扫描"压成了"对数查找"。

二分查找的递归:T(n)=T(n/2)+Θ(1)规模 n查 [0,n)半区 n/2半区 n/2每层只做 1 次比较(Θ(1)),共 log₂n 层T(n)=T(n/2)+1 ⇒ 情况2(k=0) ⇒ Θ(log n)分治把"线性扫描"压成"对数查找"——主定理一眼看出

图:二分查找递归式 T(n)=T(n/2)+1,主定理情况2 直接得 Θ(log n)

二分查找每次取中点、丢弃一半区间,规模 nn/2n\to n/2。递推式 T(n)=T(n/2)+Θ(1)T(n)=T(n/2)+\Theta(1)a=1,b=2a=1,b=2,临界值 nlog21=1n^{\log_2 1}=1f(n)=1=Θ(1log0n)f(n)=1=\Theta(1\cdot\log^0 n)情况2,直接得 Θ(logn)\Theta(\log n)

为什么是"标准答案"

任何"每次把规模除以常数"的分治,层数都是 Θ(logn)\Theta(\log n);只要每层代价是 O(1)O(1)O(n)O(n) 线性合并,总代价就是 Θ(logn)\Theta(\log n)Θ(nlogn)\Theta(n\log n)。对数与 nlognn\log n 就是分治的两张"标准名片"。

参考代码:递归版二分查找

def bisect(a, x, lo=0, hi=None):
    if hi is None:
        hi = len(a)
    if lo >= hi:
        return lo                      # 未找到,返回插入点
    mid = (lo + hi) // 2
    if a[mid] == x:
        return mid
    if a[mid] < x:
        return bisect(a, x, mid + 1, hi)   # T(n)=T(n/2)+Θ(1) ⇒ Θ(log n)
    return bisect(a, x, lo, mid)

print(bisect([1, 3, 5, 7, 9], 5))   # 2

注意:迭代写法和递归复杂度一样,但迭代只占 O(1)O(1) 栈,不会像深层递归那样爆栈(见热点⑧)。

关联推荐

评论 (0)

正文划词可点「问萝卜特」——自动发评论并由 AI 回复

加载评论中…

二分查找与主定理:为什么 log n 是分治的标准答案 | 必学必会