重谈主定理(master定理)及其证明

参考文章:

【洛谷日报#33】时空复杂度分析及master定理

李卿. 递归算法分析中主定理的应用[J]. 黑龙江科技信息, 2011(29):97+207.

Thomas H.Cormen,Charles E.Leiserson,Ronald L.Rivest,Clifford Stein. 殷建平等译. 算法导论第三版 [M]. 北京:机械工业出版社,2013,55-58.

前言:

本篇文章与我的 博客园 同步更新。

在此之前,请先阅读 【洛谷日报#33】时空复杂度分析及master定理,其中关于时间复杂度表示的基础知识不再阐述。

引出:

现在考虑一个问题:假设某算法的计算时间表示为递归式:

T(n)=2T(n2)+nlognT(1)=1

求该算法的时间复杂度。

当给你抛出这么一个题型时,你怎么办?

凭经验和感觉蒙

小几率能蒙对,但你觉得这种题CCF会送你分吗?

递归进去

像这样递归进去:

T(n)=2T(n2)+nlogn=2(2T(n4)+n2log(n2))+nlogn=2(2(2T(n8)+n4log(n4))+n2log(n2))+nlogn

每项都 n÷2,总共递归 log2n 层:

T(n)=Θ(logn(nlogn+nlog(n2)+nlog(n22)++nlog(n2log2n)))

T(n)=Θ(nlog2n)

这么做不是没有道理,但是如果 T(n)=3T(n4)+nlogn,用这种方法根本算不出来(或许可以算出来,但是操作极其麻烦)。

主定理(master定理)求解

主定理:a,b 是常数,f(n) 为额外附加值函数T(n) 为递归式 T(n)=aT(nb)+f(n)(a>0,b>1),就有:

  1. f(n)=O(n(logba)ϵ) 其中 ϵ>0 是一个常数(相当于 logba>f(n)),则有 T(n)=Θ(nlogba)
  2. f(n)=Θ(nlogba),则有 T(n)=Θ(nlogbalogn)
  3. f(n)=Ω(n(logba)+ϵ) 其中 ϵ>0 是一个常数(相当于 logba<f(n)),且对于一个常数 c<1 和所有足够大的 naf(nb)cf(n)(这一条件在这里可以暂时忽略不看,但在证明时起到至关重要的作用),则有 T(n)=Θ(f(n)).
  4. f(n)=Θ(nlogbalogkn) 其中 k1 是一个常数,则有 T(n)=Θ(nlogbalogk+1n)

这么看着有点枯燥乏味的样子,不利于理解,但如果丢掉定理四的话(毕竟CSP/NOIp好像真的没考过定理四,其实可以发现定理二和定理四其实是同一种,便于萌新理解就分开了),主定理的定义可以直接写成:

图一

(图一)

也就是 nlogbaf(n) 进行比较!

图一、算法导论和上面提过的论文没有提到过定理四,但是原来那篇日报(#33)有,对此我想说,洛谷日报真是太好了!导论不行!日报行!(老伏拉夫了

举例说明:

例一:T(n)=4T(n2)+n,此时 a=4,b=2,ϵ=1,那么 logba=log24=2,f(n)=O(nlogbaϵ)=O(n21)f(n) 成立,所以 T(n)=Θ(nlogba)=Θ(n2)

例二:T(n)=2T(n2)+n,此时 a=2,b=2,那么 logba=log22=1,f(n)=Θ(nlogba)=Θ(n)f(n) 成立,所以 T(n)=Θ(nlogbalogn)=Θ(nlogn)

例三:T(n)=4T(n2)+n3,此时 a=4,b=2,ϵ=1,那么 logba=log24=2,f(n)=Ω(nlogba+ϵ)=Ω(n2+1),对于 c=23 和够大的 n(af(nb)=4(n2)3=4(n38)=n32)(cf(n)=2n33)f(n) 成立,所以 T(n)=Θ(f(n))=Θ(n3)

例四:T(n)=2T(n2)+nlogn,此时 a=2,b=2,k=1,那么 logba=log22=1,f(n)=Θ(nlogbalogkn)=Θ(nlogn)f(n) 成立,所以 T(n)=Θ(nlogbalogk+1n)=Θ(nlog2n)

证明:

先声明:证明又长又臭,有亿点点难理解,学有余力的 dalao 可以来康康。

俗话说得好:“欲要证明master,就先画棵递归树”:

图二

(图二)

关于图二的解释及证明:

对于第 i 层(ilogbn),有 ai 个节点,而每个节点的值是 f(nbi),那么第 i 层总共的值是 aif(nbi)

对于第 logbn 层,有 alogbn 个节点,而每个节点的时间复杂度是 Θ(1),那么这一层总共的时间复杂度是 Θ(alogbn)=Θ(nlogba) 层。

对于 alogbn=nlogba 的证明:

alogbn=blogbalogbn=b(logba)(logbn)=blogbnlogba=nlogba

alogbn=nlogba 得证。

这么看,图二的递归树的总时间复杂度为 T(n)=Θ(nlogba)+j=0logbn1ajf(nbj),就是叶子节点层加上其它结点层的值。

证明*:

根据上文这个 T(n) 的时间复杂度,我们定义一个函数 g(n)

g(n)=j=0logbn1ajf(nbj)

这个 g(n) 有一些性质:

  1. f(n)=O(n(logba)ϵ) 其中 ϵ>0 是一个常数,则有 g(n)=O(nlogba)
  2. f(n)=Θ(nlogba) 时,则有 g(n)=Θ(nlogbalogn)
  3. f(n)=Ω(n(logba)+ϵ) 其中 ϵ>0 是一个常数,且对于一个常数 c<1 和所有足够大的 naf(nb)cf(n),则有 g(n)=Θ(f(n)).
  4. f(n)=Θ(nlogbalogkn) 其中 k1 是一个常数,则有 g(n)=Θ(nlogbalogk+1n)

欸!有没有发现好像在哪见过!那是因为这是我从上文复制下来的(

证明关于g函数性质*:

性质 1:

f(n)=O(n(logba)ϵ) 代入进 g(n)=j=0logbn1ajf(nbj)

g(n)=O(j=0logbn1aj(nbj)(logba)ϵ)=O(j=0logbn1aj(n(logba)ϵbj(logba)ϵ))=O(j=0logbn1n(logba)ϵ(ajbj(logba)ϵ))=O(n(logba)ϵj=0logbn1(ab(logba)ϵ)j)=O(n(logba)ϵj=0logbn1(abϵa)j)=O(n(logba)ϵj=0logbn1(bϵ)j)

然后根据等比数列求和公式化简 j=0logbn1(bϵ)j

g(n)=O(n(logba)ϵ(bϵlogbn1bϵ1))=O(n(logba)ϵ(nϵ1bϵ1))

这里回想一下 b,ϵ 的定义,(做到不忘初心牢记使命),它们是常数,所以式子中 1bϵ1 也是常数,应忽略:

g(n)=O(n(logba)ϵnϵ)=O(nlogba)

性质 1 得证。

性质 2:

性质 1 和性质 2 操作一样,就是一直代入再一直化简,将 f(n)=Θ(nlogba) 代入进 g(n)=j=0logbn1ajf(nbj)

g(n)=Θ(j=0logbn1aj(nbj)logba)=Θ(j=0logbn1aj(nlogbabjlogba))=Θ(nlogbaj=0logbn1(ajbjlogba))=Θ(nlogbaj=0logbn1(ablogba)j)=Θ(nlogbaj=0logbn11)=Θ(nlogbalogbn)

注意:这里重头戏来了!式子中的 logbn 是可以直接改底数的,因为可以通过换底公式得到对数函数都是同级的。因此我们可以把 b 改成 2(即 logbn 化成 logn):

g(n)=Θ(nlogbalogn)

性质 2 得证。

性质 3:

性质 3 是最特殊的,用 af(nb)cf(n) 递归 j 次可以得到 ajf(nbj)cjf(n)。再用这个式子套 g(n) 定义:

g(n)j=0logbn1cjf(n)g(n)f(n)j=0logbn1cjg(n)f(n)j=0cj

解释一下上面的式子,因为 c 都是正数,所以如果 g(n)f(n)j=0logbn1cj,显然 g(n)f(n)j=0cj。而这么做是为了更好证明。

接下来还是用等比数列求和公式化简:

g(n)f(n)j=0cjg(n)(11c)f(n)

你可能好奇这个等比数列求和是怎么化的,下面证明一下:

S=c0+c1+c2++c 表示 j=0cj,此时公比为 c

cS=c1+c2+c3++c,这里 +1=

(1c)S=c0=1

S=11c

j=0cj=11c

回到题目,由 g(n)(11c)f(n) 得到 g(n)=O(f(n))

而根据 g(n) 的定义 g(n)=f(n)+af(nb)+a2f(nb2)++alogbn1f(nblogbn1)f(n),得到 g(n)=Ω(f(n))

所以 g(n)=Θ(f(n))

性质 3 得证。

性质 4:

老套路,将 f(n)=Θ(nlogbalogkn) 代入进 g(n)=j=0logbn1ajf(nbj)

g(n)=Θ(j=0logbn1aj(nbj)logbalogk(nbj))=Θ(j=0logbn1aj(nlogbabjlogba)(lognlogbj)k)=Θ(nlogbaj=0logbn1(ajbjlogba)(logknlogkbj))=Θ(nlogbaj=0logbn1(ablogba)j(logknlogkbj))=Θ(nlogbaj=0logbn1logknlogkbj)=Θ(nlogba(logbnlogknj=0logbn1logkbj))=Θ(logbnlogknnlogbanlogbaj=0logbn1logkbj)

和性质 2 一样: logbn 可以直接化为 logn。然后 nlogbaj=0logbn1logkbj 是一个负数,在时间复杂度的表示中可以忽略,所以得到:

g(n)=Θ(nlogbalogk+1n)

性质 4 得证。

主定理总时间复杂度证明:

回到图二的总时间复杂度 T(n)=Θ(nlogba)+j=0logbn1ajf(nbj)

f(n)=O(n(logba)ϵ) 时:

T(n)=Θ(nlogba)+j=0logbn1ajf(nbj)=Θ(nlogba)+g(n)=Θ(nlogba)+O(nlogba)=Θ(nlogba)

f(n)=Θ(nlogba) 时:

T(n)=Θ(nlogba)+j=0logbn1ajf(nbj)=Θ(nlogba)+g(n)=Θ(nlogba)+Θ(nlogbalogn)=Θ(nlogbalogn)

f(n)=Ω(n(logba)+ϵ),且对于一个常数 c<1 和所有足够大的 naf(nb)cf(n)

T(n)=Θ(nlogba)+j=0logbn1ajf(nbj)=Θ(nlogba)+g(n)=Θ(nlogba)+Θ(f(n))=Θ(f(n))

f(n)=Θ(nlogbalogkn) 时:

T(n)=Θ(nlogba)+j=0logbn1ajf(nbj)=Θ(nlogba)+g(n)=Θ(nlogba)+Θ(nlogbalogk+1n)=Θ(nlogbalogk+1n)

主定理证毕。

后记 & 感谢名单:

在这篇文章证明的主定理只是对于 b 的幂下的,就是说向上、向下取整的没有证明,但要证明这些实在太难了,要花费更长的时间 (主要还是懒

我在查找资料的时候发现还有一种定理——Akra-Bazzi定理(打开要梯子)也是时间复杂度的。

感谢名单(排名不分先后):

@stoorz

@bruteforce_

@SSL_TJH_蒟蒻

@RABU

posted @   Jayun  阅读(3869)  评论(1编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示