跳转至

基础知识

复杂度记号

\(f(n) = O(g(n))\)\(g\)\(f\)的上界 存在\(c\)\(n_0\)\(n \geq n_0\)时,\(f(n) \leq c g(n)\)

\(f(n) = \Omega(g(n))\) \(g\)\(f\)的下界,存在\(c\)\(n_0\)\(n \geq n_0\)时,\(f(n) \geq c g(n)\)

\(f(n) = \Theta(g(n))\) \(g\)\(f\)的确界,满足\(f(n)=O(g(n))\)\(f(n)=\Omega(g(n))\)

\(f(n) = o(g(n))\) \(g\)\(f\)的严格上界,存在\(c\)\(n_0\)\(n \geq n_0\)时,\(f(n) < c g(n)\)

\(f(n) = w(g(n))\) \(g\)\(f\)的严格下界,存在\(c\)\(n_0\)\(n \geq n_0\)时,\(f(n) > c g(n)\)

主定理

\(T(n) = aT(n/b) + f(n)\)

\(a>=1 且 b>1\) 是常数,\(f(n)\) 是一个函数,\(T(n)\) 是定义在非负整数上的递归式,那么 \(T(n)\) 有如下渐进界:

  1. \(f(n) = O(n^{log_b a - \epsilon})\) 对于某个常数 \(\epsilon > 0\),则 \(T(n) = \Theta(n^{log_b a})\)
  2. \(f(n) = \Theta(n^{log_b a})\),则 \(T(n) = \Theta(n^{log_b a} \log n)\)
  3. \(f(n) = \Omega(n^{log_b a + \epsilon})\) 对于某个常数 \(\epsilon > 0\),且满足 \(a f(n/b) \leq c f(n)\) 对于某个常数 \(c < 1\) 和所有足够大的 \(n\),则 \(T(n) = \Theta(f(n))\)

这里\(a\)是子问题个数,\(b\)是子问题规模,\(f(n)\)是子问题之外,将问题分解和合并的代价。

进行一些直观理解:

  • \(f(n)\)的增长速度没有\(n^{log_b a}\)快,则\(T(n)\)的增长速度为\(n^{log_b a}\),即\(T(n) = \Theta(n^{log_b a})\)
  • \(f(n)\)的增长速度比\(n^{log_b a}\)快,则\(T(n)\)的增长速度为\(f(n)\),即\(T(n) = \Theta(f(n))\)
  • 如果增长同阶,也即\(f(n) = \Theta(n^{log_b a})\),则\(T(n)\)的增长速度为\(n^{log_b a} \log n\),即\(T(n) = \Theta(n^{log_b a} \log n)\)

但是还是要能够找到一个\(\epsilon\)才行,所以会有上图的红色区域。

常用性质

函数的阶有传递性:

\(f(n) = O(g(n)) \land g(n) = O(h(n)) \implies f(n) = O(h(n))\)

\(f(n) = \Omega(g(n)) \land g(n) = \Omega(h(n)) \implies f(n) = \Omega(h(n))\)

\(f(n) = \Theta(g(n)) \land g(n) = \Theta(h(n)) \implies f(n) = \Theta(h(n))\)

注意:\(\log_b n = o(n^\alpha)\) 对于任意\(\alpha > 0\),也就是对数增长比任何多项式增长都慢。

以及有恒等式\(a^{\log_b n} = n^{\log_b a}\)

斯特林公式:\(n! = \Theta(\sqrt{n} (\frac{n}{e})^n)\)\(n^n\)慢。

以及\(\log n! = \Theta(n \log n)\)

对于不同的\(\log\)底数,他们在阶数上都是相同的,即\(\log_a n = \Theta(\log_b n)\)

比较复杂度大小的时候,如果遇到指数很复杂的,两边取log是一个很好的简化方式,比如\((\log n)^{\log n}\)\(n^{\log \log n}\),两边取对数就变成了\(\log n \log \log n\)\(\log \log n \log n\),可以发现是同阶的。

迭代法

汉诺塔问题:

\(T(n) = 2T(n-1) + 1\)

不断用递推方程的右边替代左边,直到出现\(T(1)\),然后求解。

对于汉诺塔,\(T(n) = 2^n - 1\)

正确性验证:数学归纳

一个配套的方法是换元迭代,将对n的递推式换成对其他变元k的递推式。对k直接迭代。

递归树

把图画出来,然后求和。

每层计算量固定,只需要计算树高,树高取个\(\log\),然后乘以计算量。(就是式子里的分支代价)