数据结构之动态规划 斐波那契数列
$fib()$递归
$fib(n)=fib(n-1)+fib(n-2): {0, 1, 1, 2, 3, 5, 8, ……}$
复杂度计算
$T(0)=T(1)=1; T(n)=T(n-1)+T(n-2)+1, n>1$
令$S(n)=\frac{T(n)+1}{2}$//这是要去掉递归式里的常数
则$S(0)=1=fib(1), S(1)=1=fib(2)$
故$S(n)=S(n-1)+S(n-2)=fib(n+1) //\Phi=\frac{1+\sqrt{5}}{2}=1.61803……$
$T(n)=2*S(n)-1=2*fib(n+1)-1=O(fib(n+1))=O(\Phi ^n)=O(2^n)$
已知$\Phi^{36}=2^{25}, \Phi^{5}=10, (2^{10})^3=(10^3)^3$
$\Phi^{43}=2^{30}=10^9flo=1 sec$
$\Phi^{67}=10^14flo=10^5 sec=1 day$
递归跟踪后,先后出现递归实例$O(\Phi ^n)$个,去重后总数不超过$O(n)$种
面对递归实例爆炸而去重后数目并不多的现象,可以将已计算过的结果存下,也可以自下而上迭代
f=0;g=1;
while(0<n - - ){
g = g + f;
f = g - f;
}
return g;
(g=1,f=0;g=1,f=1;g=2,f=1;g=3,f=2;g=5,f=3;g=8,f=5;g=13,f=8……)
动态规划求解
原问题拆成若干子问题,保存子问题的解(不用多次重复求解)
public static int fib_dp(int n){ if(n==0){ return 0; } if(n == 1 || n == 2){ return 1; } int pre = 1; int ppre = 1; int result = 0; for(int i=3; i<=n; i++){ result = pre + ppre; ppre = pre; pre = result; } return result; }
应用:爬楼问题
一段楼梯有8级台阶,规定每一步可跨1级2级或3级,要登上第8级台阶,有几种不同的走法(从第1级开始)
第1级:梦开始的地方
到第2级:只跨1步,有1种。
到第3级:(1、1),(2),有2种。
到第4级:(1、1、1),(1、2),(2、1),有1+2=3种。
到第5级:(1、1、1、1),(1、1、2),(2、1、1),(2、2),(1、2、1),有2+3=5种。
到第6级:有3+5=8种。(从第4次开始,后一种情况总是前两种情况的和。)
到第7级:有5+8=13种。
到第8级:有8+13=21种。
动态规划求解最长公共子序列:
时间复杂度:
由于只需要填一个m行n列的二维数组,其中m代表第一个字符串长度,n代表第二个字符串长度,所以时间复杂度为O(m*n)