1137. 第 N 个泰波那契数https://leetcode.cn/problems/n-th-tribonacci-number/description/泰波那契数列T(n)定义如下:T(0) = 0,T(1) = 1,T(2) = 1,且在n >= 0的条件下T(n + 3) = T(n) + T(n + 1) + T(n + 2)。给你整数n,请返回第n个泰波那契数T(n)的值。
- 输入:n = 4,输出:4,解释:T(3) = 0 + 1 + 1 = 2,T(4) = 1 + 1 + 2 = 4。
- 输入:n = 25,输出:1389537。
提示:0 <= n <= 37,答案保证是一个32位整数,即answer <= 2^31 - 1。
我们用动态规划的思想来解决这个问题。
确定状态表示:根据题目要求,我们用dp[i]表示第i个泰波那契数T(i)的值。
推导状态转移方程:根据题目要求,每个泰波那契数等于前3项的和,即T(i) = T(i - 1) + T(i - 2) + T(i - 3),结合状态表示,得到dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]。
初始化:根据状态转移方程,在计算dp[0],dp[1]和dp[2]时,会越界访问dp[0]之前的值。根据题目要求,T(0) = 0,T(1) = 1,T(2) = 1,故dp[0] = 0,dp[1] = 1,dp[2] = 1。
填表顺序:根据状态转移方程,dp[i]依赖于dp[i - 1],dp[i - 2]和dp[i - 3],故应从左往右填表。
返回值:根据状态表示,最终应返回dp[n],即为第n个泰波那契数T(n)的值。
细节问题:由于下标范围是[0, n],故dp表的规模为1 x (n + 1)。防止dp[1]和dp[2]越界,应处理n < 3时的边界情况。
class Solution {
public:
int tribonacci(int n) {
// 处理边界情况
if (n == 0) {
return 0;
}
if (n == 1 || n == 2) {
return 1;
}
// 创建dp表
vector<int> dp(n + 1);
// 初始化
dp[1] = dp[2] = 1;
// 填表
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
}
// 返回结果
return dp[n];
}
};
我们可以用滚动数组的思路来优化空间复杂度。注意到状态转移方程一共涉及4项:dp[i],dp[i - 1],dp[i - 2]和dp[i - 3],我们把这4项替换成字母,得到d = a + b + c。
0 1 1 ?
a b c d
0 1 1 2
a b c d
计算完成后,只需要按照a = b,b = c,c = d的顺序赋值,就能继续填下一个位置的值了。
0 1 1 2 ?
a b c d
^ ^ ^
a b c d
0 1 1 2 4
a b c d
细节问题:赋值的顺序不能是c = d,b = c,a = b,这是因为在执行c = d之后,c的值已经被覆盖了,此时再执行b = c,b得到的就不是原来的c的值了。
class Solution {
public:
int tribonacci(int n) {
// 处理边界情况
if (n == 0) {
return 0;
}
if (n == 1 || n == 2) {
return 1;
}
// 滚动数组
int a = 0, b = 1, c = 1, d = 0;
// 填表
for (int i = 3; i <= n; i++) {
d = a + b + c;
a = b;
b = c;
c = d;
}
// 返回结果
return d;
}
};