泰波那契数 图解题解
这道题到底在问什么
- 输入
- n = 10
- 输出
- 149
最优解:为什么这么做
一句话答案:LeetCode 1137 泰波那契数用一维递推:每项等于前三项之和 T(n)=T(n-1)+T(n-2)+T(n-3),从 T0=0、T1=1、T2=1 三个种子往后加。三个变量滚动,时间 O(n)、空间 O(1),斐波那契前三项版。
泰波那契数到底在算什么
泰波那契数列和斐波那契长得像,只是把「前两项相加」换成「前三项相加」。它从 T0=0、T1=1、T2=1 起头,之后每项都等于紧挨它的前三项之和。给你 n,求第 n 项 T(n),比如 n=10 时答案 149。
为什么照定义递归会算不完
照定义写递归 T(n)=T(n-1)+T(n-2)+T(n-3),会摊成一棵疯狂分叉的树:算 T(n-1) 时又把 T(n-2)、T(n-3) 重算一遍,越往下重复越离谱,时间随 n 指数膨胀。
根子是同一个 T(k) 被反复重算。既然每项只由更小的项决定,反过来从 T0 一个个往上填,每项只算一次,算过的留给后面用。
dp 怎么定义,为什么非要三个种子
定义 dp[i] 就是第 i 个泰波那契数 T(i),下标 i 对应第几项,格子里的值就是那一项的大小。起手必须铺满三个种子:dp[0]=0、dp[1]=1、dp[2]=1。
道理在转移式(从前面几格推出这一格的那条公式)上:每项要前三项相加,想算出第一个「非种子」的 dp[3],手里得先攥着 dp[0]、dp[1]、dp[2]。斐波那契依赖前两项、两个种子够用;泰波那契依赖前三项就得多备一个。只给两个种子是最典型的错法,循环从 dp[3] 起就少一个数,推不动。
为什么前三项直接相加就是对的
转移式 dp[i]=dp[i-1]+dp[i-2]+dp[i-3] 成立,是因为泰波那契的定义本身就这么规定——它不像求最值的题要在几条来路里挑最好的,而是把前三项原样加起来。
前三项一加,第 i 项的值就被唯一定死、没有第二种可能:只要 dp[i-1]、dp[i-2]、dp[i-3] 算对,dp[i] 就一定对。从左往右填,用到的三个数都是前面填好的,链条不会断。
拿 n=10 亲手加一遍
三个种子先摆好:dp[0]=0、dp[1]=1、dp[2]=1。从 dp[3] 开始,每格都是前三格之和:
dp[3] = dp[2]+dp[1]+dp[0] = 1+1+0 = 2 dp[4] = 2+1+1 = 4 dp[5] = 4+2+1 = 7 dp[6] = 7+4+2 = 13 dp[7] = 13+7+4 = 24 dp[8] = 24+13+7 = 44 dp[9] = 44+24+13 = 81 dp[10] = 81+44+24 = 149
填到 dp[10] 得到 149,和题目答案对上,这一列填出来的数就是泰波那契的前十一项。
复杂度多少,三个种子和溢出别弄错
从 dp[3] 推到 dp[n],一共 n-2 格,每格一次加法,时间 O(n);每项只用最近三项,不必存整表,用三个变量轮转——算完一格丢掉最老的、接上新算的,空间从 O(n) 压到 O(1)。
容易踩坑的有三处:种子只铺两个,循环起不来;n≤2 没特判会取到还没准备好的项,得让 n=0 返回 0、n=1 和 n=2 返回 1;数值溢出,本题 n≤37、T(37) 还在 int 内,但项一大长得飞快,扩到更大 n 就该换更大整数类型。
▶ 动画逐步走查(共 22 步)——想跟着动画一帧帧对照就展开
- 3记住这条转移式:每一项 = 前三项之和。下面每一格都在套它。
- 4这是 dp 表,每一列 Ti 对应第 i 个泰波那契数,现在全空。从最左边的 T0 开始。
- 5第 0 项规定为 0:dp[0]=0。这是种子,不用算。
- 6第 1 项规定为 1:dp[1]=1。
- 7第 2 项也规定为 1:dp[2]=1。三个种子就位,从 T3 开始才真正用转移式。
- 8算 dp[3]:把它前面紧挨的三项加起来——dp[2]=1、dp[1]=1、dp[0]=0(高亮的三个蓝格)。
- 9三项相加得 1+1+0=2,填进 dp[3]。当前格补好,继续往右。
- 10算 dp[4]:把它前面紧挨的三项加起来——dp[3]=2、dp[2]=1、dp[1]=1(高亮的三个蓝格)。
- 11三项相加得 2+1+1=4,填进 dp[4]。当前格补好,继续往右。
- 12算 dp[5]:把它前面紧挨的三项加起来——dp[4]=4、dp[3]=2、dp[2]=1(高亮的三个蓝格)。
- 13三项相加得 4+2+1=7,填进 dp[5]。当前格补好,继续往右。
- 14算 dp[6]:把它前面紧挨的三项加起来——dp[5]=7、dp[4]=4、dp[3]=2(高亮的三个蓝格)。
- 15三项相加得 7+4+2=13,填进 dp[6]。当前格补好,继续往右。
- 16算 dp[7]:把它前面紧挨的三项加起来——dp[6]=13、dp[5]=7、dp[4]=4(高亮的三个蓝格)。
- 17三项相加得 13+7+4=24,填进 dp[7]。当前格补好,继续往右。
- 18算 dp[8]:把它前面紧挨的三项加起来——dp[7]=24、dp[6]=13、dp[5]=7(高亮的三个蓝格)。
- 19三项相加得 24+13+7=44,填进 dp[8]。当前格补好,继续往右。
- 20算 dp[9]:把它前面紧挨的三项加起来——dp[8]=44、dp[7]=24、dp[6]=13(高亮的三个蓝格)。
- 21三项相加得 44+24+13=81,填进 dp[9]。当前格补好,继续往右。
- 22算 dp[10]:把它前面紧挨的三项加起来——dp[9]=81、dp[8]=44、dp[7]=24(高亮的三个蓝格)。
- 23三项相加得 81+44+24=149,填进 dp[10]。当前格补好,继续往右。
- 24最右 dp[10]=149 就是 T(10)。整张表从左填到右,每格都只是前三格之和。
⚠️ 容易写错的地方
✗ 错:把基值记成两个
✓ 对:T0=0、T1=1、T2=1 共三个种子
泰波那契递推依赖前三项,少一个种子起不来
✗ 错:n≤2 不特判
✓ 对:n=0 返回 0,n=1/2 返回 1
循环从 i=3 起,前三项要直接给
✗ 错:大 n 溢出
✓ 对:用 long 累加再转回
本题 n≤37,T(37) 仍在 int 范围内;扩展到 T(38) 才会超 int,用 long 更稳
完整代码(Python / C++ / Java)
Python
def tribonacci(n):
if n == 0: return 0
if n <= 2: return 1
a, b, c = 0, 1, 1 # T(i-3), T(i-2), T(i-1)
for _ in range(3, n + 1):
a, b, c = b, c, a + b + c
return cC++
int tribonacci(int n){
if(n == 0) return 0;
if(n <= 2) return 1;
long a = 0, b = 1, c = 1;
for(int i = 3; i <= n; ++i){
long d = a + b + c;
a = b; b = c; c = d;
}
return (int)c;
}Java
class Solution {
int tribonacci(int n){
if (n == 0) return 0;
if (n <= 2) return 1;
long a = 0, b = 1, c = 1;
for (int i = 3; i <= n; i++) {
long d = a + b + c;
a = b; b = c; c = d;
}
return (int) c;
}
}复杂度
时间
O(n)
从 3 到 n 一遍线性递推,每格 O(1)
空间
O(1)
只需滚动保存最近三项
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 泰波那契数 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
泰波那契和斐波那契(LeetCode 509)到底差在哪?+
递推骨架一模一样,都是「若干个前项相加」。斐波那契是前两项相加、两个种子(0、1);泰波那契是前三项相加、三个种子(0、1、1)。会了一个,另一个只是把相加的项数和种子数各加一,滚动变量从两个变成三个。
为什么 dp[i] 只依赖前三项就能优化到 O(1) 空间?+
算 dp[i] 时只会用到 dp[i-1]、dp[i-2]、dp[i-3],更早的项再也用不上。所以不必留整个数组,拿三个变量存住最近三项,每算出一项就整体往前挪一格,空间从 O(n) 降到 O(1),结果不变。
n=0、1、2 这几个小输入为什么要单独处理?+
循环是从第 3 项才开始套转移式的,前三项属于「规定值」,不参与计算。如果不给 n≤2 单独返回(n=0 给 0,n=1、n=2 给 1),循环要么一次都不进、要么取用还没设好的项,就会出错。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 泰波那契数 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。