递归式的时间复杂度通常都不太好理解,求证,算法导论里给出了三种求解递归式时间复杂度的方法:html
一、代换法 (凭直觉,经验)git
实际使用的是概括法,即根据直觉经验判断结果应该是什么,而后再概括求解。github
先带入常量c,而后概括得出这样的c存在算法
Ex1: T(n) = T(n-1) + n, 咱们先猜想解是O(n^2) 假定对于任意的m<n, T(m) <= cm^2,带入递归式 T(n) <= c(n-1)^2 + n = cn^2 - 2cn + c + n = cn^2 - ((2c-1)n - c) <= cn^2 可见只要c>1,n>0,而n本就要求大于0,故((2c-1)n - c)>0,故T(n)<=O(n^2),得证 Ex2:T(n) = 2T(n/2)+n, 咱们先猜想解是O(nlgn) 假定对于任意的m<n, T(m)<=cmlgm, 带入递归式可得 T(n) <= 2c(n/2)lg(n/2)+n = cnlg(n/2)+n <= cnlgn-cnlg2+n = cnlgn-(c-1)n 可见只要c>1,(c-1)n > 0, 故T(n)<=cnlgn,因此咱们的猜想是正确的,因此得证
但这不是首选的方法,由于猜想的形式很难,须要积累不少的求解的经验函数
二、递归树法工具
递归树法不是那么精确,取决于你画递归树的精确度。用递归树来猜想上界,而后用上面的代换法来证实正确性post
Ex1: T(n) = T(n-1) + O(n) T(1) = 1 n n / T(n-1) n-1 / T(n-2) n-2 ... . / . T(1) 1 树高度n,1+2+...+n=n(n-1)/2,即O(n^2) Ex2:T(n) = 2T(n/2)+O(n) T(1) = 1 n n / \ T(n/2) T(n/2) n/2+n/2=n / \ / \ T(n/4) T(n/4) T(n/4) T(n/4) n/4+...=n ... / \ n/8+...=n T(1) T(1) 1+1+...=n 树高度log2^n,即log2^n个n即nlog2^n,即O(nlog2^n) Ex3:T(n) = 3T(n/2)+O(n) T(1) = 1, 3T(n/2)下级分3个 n n | | | T(n/2) T(n/2) T(n/2) (3/2)n | | | | | | ... T(n/4) T(n/4) T(n/4) T(n/4) T(n/4) T(n/4) (3/2)^2 n ... / T(1) 由于2倍数递减,因此树高度log2^n,(1+3/2+(3/2)^2+(3/2)^3...)*n=(1 + (3/2)(1-(3/2)^log2^n)/(1-(3/2)))*n,即O(nlog2^3)即O(n^1.585) 注:等比数列前n项和公式为:Sn=首项*(1-公比的n次方)/(1-公比)
3. 主方法(首推).net
主方法使用的状况是递归式知足T(n)=aT(n/b)+f(n)T(n)=aT(n/b)+f(n),在这种状况下主方法假设子问题具备相同的大小,主方法是一个用来解递归式渐进时间复杂度的黑盒工具。code
下面是简洁描述版本htm
- a:子问题数量
- b:子问题大小的所见系数
- d:递归过程以外的运行时间对问题规模n的指数系数
- a, b, d独立于n
Case1中的log函数没写base,由于这里得base对时间复杂度的影响仅仅在常系数下,而Case3中的log函数在指数上,因此不能忽略
Ex:
T(n)=3T(n/4)+n2: a=3 b=4 d=2, 3<16,a<b^d, case2, 得O(n^d)=O(n^2) T(n)=2T(n/4)+√n a=2 b=4 d=1/2, 2=2, a=b^d, case1, 得O(n^dlogn)=O(n½logn) T(n)=4T(n/4)+√n a=4 b=4 d=1/2, 4>2, a>b^d, case3, 得O(n^logb^a)=O(n) T(n)=2T(n/2)+nlgn 由表达式得知,n^logb^a=n^log2^2, 因为 f(n)/n^logb^a=nlgn/n=lgn, 对于 任意的 ω, 都不存在 lgn>n^ω, 故此不可被主方法求解。
引例:
http://raytaylorlin.com/Tech/algorithm/master-method/
http://blog.csdn.net/weixin_36497128/article/details/52914255
http://haiyangxu.github.io/posts/2014/2014-05-03-mastermethod.html