TL;DR
Slide a 3-wide window of previous terms forward β O(n) time, O(1) space.
The recurrence
T(k) = T(k-1) + T(k-2) + T(k-3) for k >= 3
T(0) = 0, T(1) = 1, T(2) = 1
Approach 1 β Brute-force recursion
Transcribe the recurrence; each call fans out into three.
class Solution:
def tribonacci(self, n: int) -> int:
if n == 0:
return 0
if n <= 2:
return 1
return (self.tribonacci(n - 1)
+ self.tribonacci(n - 2)
+ self.tribonacci(n - 3))
Complexity: ~O(3^n) time, O(n) stack.
Why the constraints kill it: at n = 37 the three-way branching re-derives lower terms billions of times β far slower than the linear methods below despite the small n.
Approach 2 β Top-down memoization
The insight: there are only n + 1 distinct terms; cache each so it is computed once.
from functools import cache
class Solution:
def tribonacci(self, n: int) -> int:
@cache
def T(k: int) -> int:
if k == 0:
return 0
if k <= 2:
return 1
return T(k - 1) + T(k - 2) + T(k - 3)
return T(n)
Complexity: O(n) time, O(n) space (cache + stack).
Approach 3 β Bottom-up tabulation
The insight: compute T(0), T(1), β¦ , T(n) in order so each termβs three predecessors are already stored.
class Solution:
def tribonacci(self, n: int) -> int:
if n == 0:
return 0
if n <= 2:
return 1
dp = [0] * (n + 1)
dp[1] = dp[2] = 1
for k in range(3, n + 1):
dp[k] = dp[k - 1] + dp[k - 2] + dp[k - 3]
return dp[n]
Walkthrough (n = 4): dp = [0, 1, 1, ?, ?]. dp[3] = 1+1+0 = 2, dp[4] = 2+1+1 = 4. Return 4. β
Complexity: O(n) time, O(n) space.
Approach 4 β Space-optimized (rolling triple)
The insight: T(k) reads only the previous three terms, so three variables replace the whole table.
class Solution:
def tribonacci(self, n: int) -> int:
if n == 0:
return 0
if n <= 2:
return 1
a, b, c = 0, 1, 1 # T(0), T(1), T(2)
for _ in range(3, n + 1):
a, b, c = b, c, a + b + c
return c
Walkthrough (n = 25): starting (a,b,c) = (0,1,1), each step drops the oldest term and appends the new sum. After 23 iterations c = 1389537. β
Complexity: O(n) time, O(1) space.
Common pitfalls
- Wrong base cases. Note
T(2) = 1, not 2. A wrong seed (e.g. treating it like Fibonacci with only two bases) shifts the whole sequence.
- Not short-circuiting
n < 3. The rolling-triple loop assumes at least the three seeds exist; return the base values directly for n = 0, 1, 2.
- Sliding the window in the wrong order. Use simultaneous assignment
a, b, c = b, c, a+b+c; updating a before computing the sum corrupts it.
Pattern takeaway
Tribonacci generalizes the Fibonacci DP from a 2-wide to a 3-wide look-back window β the same βsplit on the last decisionβ logic, just with one more term in the sum. The reusable rule: when a recurrence depends on a fixed constant number w of previous states, tabulate bottom-up and then keep only the last w values as rolling variables for O(1) space.