斐波那契数列与剪绳子
题目来源于《剑指Offer》的第10,14题,都可以用动态规划的思路来解决问题。
斐波那契数列
斐波那契数列是数学中非常有名的数列,在中国也可以叫杨辉三角。其递推公式简单明了:
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
(
n
>
1
且
n
∈
N
+
)
f(n) = f(n-1) + f(n-2) (n>1且 n\in N^+)
f(n)=f(n−1)+f(n−2)(n>1且n∈N+)
f
(
n
)
=
{
0
n
=
0
1
n
=
1
f
(
n
−
1
)
+
f
(
n
−
2
)
n
>
1
且
n
∈
N
+
f(n)= \left\{ \begin{array}{lcl} 0 & & n=0\\ 1 & & n=1\\ f(n-1) + f(n-2) & & n>1且n\in N^+ \end{array} \right.
f(n)=⎩⎨⎧01f(n−1)+f(n−2)n=0n=1n>1且n∈N+
对于求解f(n)这个问题的求解就可以从两个方向着手,
-
第一是自顶而下递归的方法;
-
第二是自底向上的方法。
所谓自顶而下的方法即是当我们要求解 f ( n ) f(n) f(n)的时候,先去求解 f ( n − 1 ) f(n-1) f(n−1)和 f ( n − 2 ) f(n-2) f(n−2),当遇到已知的 f ( 1 ) f(1) f(1)和 f ( 0 ) f(0) f(0)时,递归终止。写成代码可以为
int FibSeq(int n){
if(n==0){
return 0;
}
if(n==1){
return 1;
}
return FibSeq(n-1) + FibSeq(n-2);
}
代码十分简略,分析其时空复杂度,时间上由于计算每一个f(n)都要分解为两个f(n-1)和f(n-2),时间复杂度为 O ( 2 n ) O(2^n) O(2n)。每次递归都需要系统在堆栈分配一个空间,所以他的空间复杂度也为 O ( 2 n ) O(2^n) O(2n)。
通过以上的分析可以看出,这种递归方法的效率不能接受。但为什么会这么多呢?
通过qiuxiaonao画出的用户迭代图可以看出,f(1)和f(2)等被多次计算,且回顾转移方程,我们只需要保存最近的两个结果f(n-1)和f(n-2)即可计算出f(n)。
int FibSeq(int n){
if(n==0){
return 0;
}
if(n==1){
return 1;
}
int preRes[2] = {0,1};
int prePoint = 0;
int res = 0;
for(int i=2;i<=n;i++){
res = preRes[0] + preRes[1];
preRes[prePoint] = res;
prePoint = 1 - prePoint;
}
return res;
}