#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int A[21]; // n 最大是 20,因此开个大小为 21 的数组即可(从 A[1] 开始)
A[1] = 0;
if (n >= 2) A[2] = 1;
if (n >= 3) A[3] = 1;
//用数组替代递归
for (int i = 4; i <= n; i++) {
A[i] = A[i - 3] + 2 * A[i - 2] + A[i - 1];
}
cout << A[n] << endl;
return 0;
}
递归写法(你最开始的版本):
cpp复制编辑int res(int n){
if(n==1) return 0;
if(n==2 || n==3) return 1;
return res(n-3) + 2*res(n-2) + res(n-1);
}
看似很简洁,但有一个致命缺点:它会重复计算大量相同子问题!
🔍 举个例子:算 res(6) 时你会发生什么?
- res(6) = res(3) + 2×res(4) + res(5)
- 但要算 res(5) 又要算 res(3)、res(2)、res(4)
- 然后又要算 res(3) ……重复算!
所以递归树会爆炸一样增长,大量重复计算导致效率低下!
⏱ 时间复杂度
- 原始递归是指数级的:O(3^n)
- 用数组存中间值,只需顺序扫一遍,变成线性复杂度 O(n)!
💡 再回答:怎么想到用数组?
你只要遇到这种模式:
“一个值依赖前几个值,而且每个值只用一次”,就该想到:用数组来存结果,避免重复计算,这是所谓的“记忆化”或“动态规划(DP)思想)”。
🚀 实用判断标准:什么时候该用数组(动态规划)
如果你看到:
- 递归公式(比如 A[n] = A[n-1] + ...)
- 会重复算同一个值(比如 res(4) 在多处出现)
- 题目给出的 n 比较大(比如 n ≤ 10^5)
就几乎可以确定:
✅ “用数组存中间值,别重复算了!”
✅ 数组写法回顾:
cpp复制编辑int A[21];
A[1] = 0;
A[2] = 1;
A[3] = 1;
for (int i = 4; i <= n; i++) {
A[i] = A[i - 3] + 2 * A[i - 2] + A[i - 1];
}
这个写法每个值只算一次,总共 n 次循环,每次计算都非常快(只是加法和乘法),效率就是最优的。

京公网安备 11010502036488号