We start with the most straightforward approach by directly translating the Fibonacci definition into code.
n-1
and n-2
. Base cases are defined for n = 0
(returns 0) and n = 1
(returns 1).fib(n)
that checks base cases.fib(n-1)
and fib(n-2)
.n
.n
. We need to eliminate redundant calculations.
To address the inefficiency of redundant calculations, we introduce memoization to store previously computed values.
memo
initialized with base cases {0:0, 1:1}.f(x)
that checks if x
is in memo
. If so, return the stored value; otherwise, compute and store f(x-1) + f(x-2)
.f(n)
to get the result.n
values, and the recursion stack uses O(n) space.
We shift to an iterative approach using dynamic programming to avoid recursion and maintain clarity.
n = 0
or n = 1
, return 0 or 1.dp
of size n+1
, initialized with zeros.dp[0] = 0
and dp[1] = 1
.i = 2
to n
, setting dp[i] = dp[i-2] + dp[i-1]
.dp[n]
.n-1
iterations with constant-time operations.dp
array stores n+1
values.
We optimize the DP solution by only storing the two numbers needed for each step, reducing space complexity.
dp[i-2]
and dp[i-1]
to compute dp[i]
. Instead of an array, we can use two variables to track the previous and current numbers, updating them iteratively.n = 0
and 1 for n = 1
.prev = 0
and cur = 1
for F(0) and F(1).i = 2
to n
, updating prev
and cur
using a simultaneous assignment: prev, cur = cur, prev + cur
.cur
, which holds F(n).n-1
iterations with constant-time updates.n
.
The Fibonacci sequence is a classic mathematical series where each number is the sum of the two preceding ones, starting from 0 and 1. Formally, the sequence begins as: 0, 1, 1, 2, 3, 5, 8, 13, ... and so on. The goal of this problem is to return the n
th Fibonacci number using an efficient and optimized approach. While recursion is a natural way to define the sequence, it quickly becomes inefficient due to overlapping subproblems and redundant calculations.
Instead of using recursion, the optimal way to compute the nth Fibonacci number is with a bottom-up dynamic programming technique. This method avoids recomputation and builds the solution iteratively from the base cases. It also takes advantage of the fact that we only need to remember the last two values at any time, making it highly space-efficient.
n
is 0, return 0; if n
is 1, return 1. These are the first two Fibonacci numbers and serve as our starting point.prev = 0
and cur = 1
, representing fib(0)
and fib(1)
.i = 2
to n
. At each step, compute the next Fibonacci number as next = prev + cur
. Then, update prev
and cur
accordingly: prev = cur
and cur = next
.cur
will contain the value of fib(n)
, which is returned as the result.Let’s say n = 5
. The loop would proceed as follows:
So fib(5)
= 5.
Time Complexity: The algorithm runs in O(n) time, as it processes each number from 2 to n exactly once.
Space Complexity: O(1), since it uses only two variables (prev
and cur
) to track the most recent Fibonacci numbers.
This solution avoids the exponential blowup of recursive approaches and the memory overhead of full dynamic programming tables. It combines the clarity of iteration with the efficiency of constant-space optimization. As a result, it's ideal for large values of n
and is commonly used in production environments or competitive programming scenarios.