信息与计算科学导论02
2021-01-06 22:48:00

这里的递归实际上也可以理解为递推

##Karatsuba算法

计算界次为\(n\)的多项式乘积,\(naive\)做法需要计算\(n^2\)

一个本科生(!!!)提出了这样的算法。考虑计算\(\left(ax+b\right)\left(cx+d\right)\)

展开就是\(acx^2+\left(ad+bc\right)x+bd\),其中\(ac\)\(bd\)无法避免,而\(\left(ad+bc\right)=\left(a+b\right)\left(c+d\right)-ac-bd\),这样我们只需要计算\(\left(ad+bc\right)\)\(ac\)\(bd\)就可以了,这样就减少了\(\frac{1}{4}\)的乘法次数

再套入递归中,可以得到这样一个乘法次数的计算公式\(T\left(n\right)=3T\left(\lfloor\frac{n}{2}\rfloor\right)\),注意这个不是时间复杂度,不然还要加上后面加法的n次循环(这样做只是为了方便引入递归方程的概念)

考虑怎么解这个东西。只需要不停地拆开就可以得到\(T\left(n\right)=3^{\log_{2}{n} }\times T_0\),其中\(T_0\)是一个与n无关的常数,所以我们可以认为\(T\left(n\right)=3^{\log_{2}{n} }=n^{\log_2{3} }\),等号的由来可以两边取对数

这种形式的的方程被称为递归方程(recurrence equation),通常这类问题没有一般做法,最好的做法是guess and prove……

##解的结构

这里讨论形如\(T\left(n\right)=f\left(n\right)+\sum\limits_{i=1}^{k}{a_i T\left(n-i\right)}\)的方程的解的结构,当然括号内部还可以更复杂,这里只是一个简单的情形

类比线性代数,递归方程也有所谓的常系数线性齐次递归方程(\(f\left(n\right)=0\)的时候)。方程的解同样可以表示为若干通解和特解的和的集合

通解:指令\(f\left(n\right)=0\),得到的递归方程的所有

特解:指带入原方程后满足递归方程的一个解

怎么证明呢?不妨设\(T_0\left(n\right)\)是一个通解,\(T_1\left(n\right)\)是一个特解

\(T_0\left(n\right)+T_1\left(n\right)=f\left(n\right)+\sum\limits_{i=1}^{k}{a_i\left({T_0\left(n-i\right)+T_1\left(n-i\right)}\right)}\)

也满足这个递归方程,因此我们说\(T_0\left(n\right)+T_1\left(n\right)\)也是原方程的一个解。类似地我们可以得到特解加上任意一个通解都是原方程的解

反过来也是一样的,只需要做差就行了

##特征方程求解

对于常系数线性齐次递推,我们(教材)猜测解的形式可以是等比数列(guess)

带入看看就是\(V\cdot p^n=V\sum\limits_{i=1}^{k}{a_i\cdot p^{n-i} }\),这里\(V\)是任意常数

这是一个一元\(k\)次方程,也是它的特征方程,特征方程的根带入都满足常系数线性齐次幂递归方程。为了简便讨论这里假设没有重根

由解的结构我们知道,这k个通解加起来得到的仍然是原方程的解,并且每一项的系数\(V\)是不一样的

怎么证明这是唯一的解呢?假设存在另一个解\(S\left(n\right)\),则可以列出线性方程组。这个方程组的系数矩阵是范德蒙矩阵,于是就完了。

对于有重根的情况,解可以写成\(\sum\limits_{i=1}^{k-L}\left({a_i\cdot\sum\limits_{j=1}^{L_i}{\left({n^{j-1}\cdot x_i}\right)} }\right)\)

其中\(L\)是不同根的数量,Li是重数

证明:考虑多项式\(F\left(x\right)=x^n-\sum\limits_{i=1}^k{a_i\cdot x^i}\)

\(x_1\)是多项式的二重根,则它是\(F'\left(x\right)\)的单根,即\(F'\left(x\right)=nx^{n-1}-\sum\limits_{i=1}^k{a_i\cdot i\cdot x^{i-1} }\)

两边同事乘上x得到\(xF'\left(x\right)=nx^n-\sum\limits_{i=1}^k{a_i\cdot i\cdot x^i}\),带入\(x=x_1\)恰好等于0

也就是说,\(n\cdot {x_1}^n\)也是这个递归方程的解,解就可以写成类似\(\left(1+n\right){x_1}^n\)这种形式了

多重根也是类似的,这里就不推了(懒)

这种方法的难点一般在找一个特解和解特征方程。找特解需要一点智慧,而高次方程通常都很不好解……

##生成函数

这是我最喜欢的方法;-P

考虑这样一个函数\(F(x)=\sum\limits_{i=0}^{\infty}{T\left(i\right)x^i}\),它包含了一个数列的所有信息,并且可以作为一个整体处理

这样的东西就是生成函数(Generating Function),也被称为母函数/形式幂级数。在这里我们不关心它是否收敛,而只在乎它的系数,x只是一个占位符号

以斐波那契数列为例子,\(F_n=F_{n-1}+F_{n-2}\)\(F_0=F_1=1\)就可以写成\(G(x)=xG(x)+x^2G(x)+1\)

化简就得到\(G(x)=\frac{1}{1-x-x^2}\)

看起来很炫酷,但是你这一顿操作也没有得到数列公式啊?

首先考虑一个等比数列\(T(n)=p^n\),则很容易写出这个数列的生成函数\(H(x)=\sum\limits_{i=0}^{\infty}{\left(px\right)^{i} }\)

既然是等比数列,那么就可以写成\(H(x)=\frac{1}{1-px}\),之所以略去了一项是因为我们可以令x任意取值使得这一项是无穷小

这提示我们可以把\(G(x)\)拆成等比数列之和,于是这个就很简单了

如果不能裂项怎么办?再考虑\(P(x)=\frac{1}{\left(1-px\right)^k}\)

观察第l项的系数,这里是k个等比数列相乘,这k个项的未知数上指数之和为l,p的指数之和也为l,这里用隔板法就可以做了,系数就是\(\binom{l+k-1}{k-1}\cdot p^l\)

这里得出的结论和上面的方法是一致的,也就是我们总能得到若干个等比数列的线性组合,它满足递归方程

有一点非常重要的是,在使用生成函数方法时,要小心处理前k项的值,如果是未知的最好设出来,不然会有漏解的情况。不过有的时候用这种方法求一个特解也是极好的,结合上面的方法就很好啦~

还有一些生成函数的运算法则,这个只需要知道两个生成函数相乘得到的是卷积就可以了,剩下的都比较简单

##算子

这个听得比较懵逼,但是dl说它足够抽象,可以带来新的视角(囧),先随便写写回来填坑

算子可以理解为是一个对数列的操作,即\(opt(T(n))\)得到得还是一个数列。我们把能使一个数列变成0的算子称为消去子(annihilator)

一个想法是,如果我们找到了把\(T(n)\)消成0的算子g,和g能消去的所有数列的集合\(P\),那么我们就可以认为是找到了所有的解(饶舌)

这个想法看上去不那么直观,甚至有点刻意的味道……

课件给出了两个最基本的算子\(L\)\(c\),分别表示把数列左移一位、每一项乘上常数c

习题中出现的两种算子\(\triangle\)\(\sum\)分别表示差分和求和(可以理解为求导和积分),类似的甚至有分步积分的形式

法则:

  1. 基础的两种消去子满足交换律、结合律(显然)

  2. 假如算子A消去了F,B消去了G,则AB能消去F+G

这里证明一下法则2:\(AB(F+G)=ABF+ABG=B(AF)+A(BG)=0\)

例子:解递归方程\(T(n)=2T(\sqrt{n})+\log n\)

注意到我们知道的递归方程解法都只和加减法有关,于是考虑变形。令\(n=2^k\),则有\(T(2^k)=2T(2^{\frac{k}{2} })+k\)

\(t(k)=T(2^k)\),则有\(t(k)=2t(\frac{k}{2})+k\),故技重施再令\(k=2^u\),则\(t(2^u)=2t(2^{u-1})+2^u\)

于是\(t'(u)=2t'(u-1)+2^u\)

先去掉\(2^u\)的项观察齐次的部分\(t'(u)=2t'(u-1)\),这个东西的消去子是\((L-2)\)

把这个算子施加在数列上可以得到\((L-2)t'(u)=Lt'(u)-2t'(u)=t'(u+1)-2t'(u)=2^{u+1}\),这一步还是很好理解的

那么我们就得到了一个新的数列\((L-2)t'(u)=2^{u+1}\),这个东西的消去子又是\((L-2)\),于是\((L-2)^2t'(u)=0\)

这个消去子能消去哪些数列呢?类比消去子和特征方程,不难发现这个东西能消去形如\((c_1+c_2n)\cdot 2^n\)的数列

因此有\(t'(u)=(c_1+c_2u)\cdot 2^u\),即\(t(k)=(c_1+c_2\cdot\log k)\cdot k\)

因此有\(T(n)=\log n\cdot(c_1+c_2\cdot \log\log n)\)

##渐进解

很多时候(大部分时候)我们是不能得出递归方程的精确解的,通常我们只能得到一个渐进意义下的解(但这不意味着我们不关心确解,当然越精确越好~)

渐进意义下(asymptotically)有点类似数学分析里的等价无穷大/等价无穷小

我们称函数\(f(x)\)的增长速度在渐进意义下不超过\(g(x)\),代表\(\exists N,M>0\),当\(n>N\)时,恒有\(f(x)\le M\cdot g(x)\)成立,即\(\lim\limits_{n\rightarrow \infty}{\frac{f(x)}{g(x)} }< M\),其中\(M\) 是个常数。

如果这里的\(M\)是0,我们认为\(f(x)\)也是不超过\(g(x)\)的。

上述两种情况记作\(f(x)=O(g(x))\),这实际上是一个不等号,包含了渐进意义下等价和小于两种情况(M是否为0)

需要注意的是,这里我们研究的函数可以认为都是非负的、定义域在正整数上的函数。因为这里的分析来源于算法的复杂度分析,倘若一个算法的复杂度和输入规模无关(或者说消耗时间为负数,它越跑越快),那么我们就没有什么必要研究这个算法了……

同时还有如下定义:

  1. \(f(x)=\Theta(g(x))\iff f(x)=O(g(x))\)\(g(x)=O(f(x))\),这样就排除了\(M=0\)的情况

  2. \(f(x)=o(g(x))\iff g(x)=O(f(x))\)

不难发现,这三种符号对应了不同的二元关系(联系2、3章),所有的多项式(这里所说的多项式指数可以是实数,甚至可以带log等函数)都可以由一个最简单的形式代表

还有一个很有意思的结论:\(\sum\limits_{i=1}^{k}{f_i(n)}\le\sum\limits_{i=1}^{k}{f_{max}(n)}=k\cdot f_{max}(n)=\Theta(f_{max}(n))\),这里\(k\)是和n无关的常数。这个结论写出来就证明完了

##Master Theorem

这个太强了!之前看的一直是简略版本,这里是一个更加详尽的版本

考虑形如\(T\left(n\right)=aT\left(\lfloor\frac{n}{b}\rfloor\right)+f(n)\)的递归方程

分三种情况:

  1. \(f(n)=\Theta\left(n^c\right)\),且\(c<\log_ba\),那么\(T\left(n\right)=\Theta\left(n^{\log_ba}\right)\)

  2. \(f(n)=\Theta\left(n^c\right)\),且\(c>\log_ba\),且\(f(n)\)满足正则条件(regular condition),那么\(T\left(n\right)=\Theta\left(n^c\right)\)

  3. \(f(n)=\Theta\left(n^{\log_ba}\log^k n\right)\),且\(k> -1\),则\(T\left(n\right)=\Theta\left(n^{\log_ba}\log^{k+1}n\right)\)

正则条件指的是对于函数\(f(n)\)\(\exists d< 1\),当n充分大时,满足\(a\cdot f\left(\frac{n}{b}\right)< d\cdot f\left(n\right)\)

注意到这里给出的都是\(\Theta\),这可比网上一搜一大堆的\(O\)强多了

一个通俗的理解是,考虑等号右边两项哪个更大,则主要的复杂度取决于哪个。如果要证明可以把递归拆开然后用等比数列求和的公式,讨论公比就可以得到这个结论了。实在不行归纳也可以证明

有的时候不能用注定理,比如说\(f(n)=n^{1-\frac{1}{n} }\),这里不存在任何一个\(c=1-\frac{1}{n}\)