题目要求
动规五部曲:
这⾥我们要⽤⼀个⼀维
dp
数组来保存递归的结果。
1.
确定
dp
数组以及下标的含义
dp[i]的定义为:第
i
个数的斐波那契数值是
dp[i]。
2.
确定递推公式
为什么这是⼀道⾮常简单的⼊⻔题⽬呢?
因为题⽬已经把递推公式直接给我们了:状态转移⽅程
dp[i] = dp[i - 1] + dp[i - 2];
3. dp
数组如何初始化
题⽬中把如何初始化也直接给我们了,如下:
dp[0]=0;
dp[1]=1;
4.
确定遍历顺序
从递归公式dp[i] = dp[i - 1] + dp[i - 2];
中可以看出,
dp[i]
是依赖
dp[i - 1]
和
dp[i - 2]
,那么遍历的顺序⼀定是从前到后遍历的。
5.
举例推导
dp
数组
按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2]
,我们来推导⼀下,当
N
为
10
的时候,
dp
数组应该是如下的数列:
0 1 1 2 3 5 8 13 21 34 55
如果代码写出来,发现结果不对,就把
dp
数组打印出来看看和我们推导的数列是不是⼀致的。
以上我们⽤动规的⽅法分析完了,
C
代码如下:
int fib(int n){
int dp[n+1];
if(n<=1)
return n;
else
{
dp[0]=0;
dp[1]=1;
for(int i=2;i<=n;i++)
dp[i]=dp[i-1]+dp[i-2];
return dp[n];
}
}
C++
代码如下:
class Solution {
public:
int fib(int N) {
if (N <= 1) return N;
vector<int> dp(N + 1);
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= N; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[N];
}
};
当然可以发现,我们只需要维护两个数值就可以了,不需要记录整个序列,所以for循环中的内容可以改成如下所示:
for (int i = 2; i <= N; i++) {
int sum = dp[0] + dp[1];
dp[0] = dp[1];
dp[1] = sum;
}
改过之后时间复杂度不变依旧是O(n),而空间复杂度由原来的O(n)转变为O(1)。
提交结果显示正确。