1. Introduction
The Fibonacci sequence is a classic sequence where each number is the sum of the two preceding ones:
F(0) = 0 F(1) = 1 F(n) = F(n-1) + F(n-2) for n >= 2
Example sequence:
0, 1, 1, 2, 3, 5, 8, 13, 21, ...
Problem Statement (Basic Coding Problem):
Given an integer
n
, computeF(n)
– the n-th Fibonacci number.
Fibonacci problems are fundamental because they teach recursion, dynamic programming, and optimization.
2. When to Use Fibonacci Pattern
Use this pattern when:
- A problem involves sequential recurrence relations.
- Subproblems overlap and repeated computation occurs.
- Each element depends on one or more previous elements.
- Problems involve counting sequences, paths, or ways.
Problem Indicators:
- “Count ways to climb stairs”
- “Number of sequences or paths”
- “Recursive dependencies with previous results”
3. Core Idea
At each step, the problem can be solved by choosing between a set of previous states:
F(n) = F(n-1) + F(n-2)
The key is overlapping subproblems, which makes dynamic programming or memoization optimal.
4. Standard Solutions
4.1 Naive Recursion
public int fibRecursive(int n) { if (n == 0) return 0; if (n == 1) return 1; return fibRecursive(n-1) + fibRecursive(n-2); }
- Time Complexity: O(2^n)
- Space Complexity: O(n) (recursion stack)
4.2 Top-Down DP (Memoization)
public int fibTopDown(int n) { int[] memo = new int[n+1]; Arrays.fill(memo, -1); return helper(n, memo); } private int helper(int n, int[] memo) { if (n == 0) return 0; if (n == 1) return 1; if (memo[n] != -1) return memo[n]; memo[n] = helper(n-1, memo) + helper(n-2, memo); return memo[n]; }
- Time Complexity: O(n)
- Space Complexity: O(n)
4.3 Bottom-Up DP (Tabulation)
public int fibBottomUp(int n) { if (n == 0) return 0; int[] dp = new int[n+1]; dp[0] = 0; dp[1] = 1; for (int i = 2; i <= n; i++) { dp[i] = dp[i-1] + dp[i-2]; } return dp[n]; }
- Time Complexity: O(n)
- Space Complexity: O(n)
4.4 Space-Optimized DP
public int fibOptimized(int n) { if (n == 0) return 0; if (n == 1) return 1; int prev1 = 0, prev2 = 1; for (int i = 2; i <= n; i++) { int curr = prev1 + prev2; prev1 = prev2; prev2 = curr; } return prev2; }
- Time Complexity: O(n)
- Space Complexity: O(1)
5. Fibonacci Pattern Variants
Many problems can be reduced to Fibonacci-like recurrences.
5.1 Climbing Stairs Problem
Problem:
Given
n
stairs, count how many distinct ways to climb to the top if you can take 1 or 2 steps at a time.
Observation:
ways(n) = ways(n-1) + ways(n-2)
Java Solution:
public int climbStairs(int n) { if (n <= 1) return 1; int oneStep = 1, twoStep = 1; for (int i = 2; i <= n; i++) { int curr = oneStep + twoStep; twoStep = oneStep; oneStep = curr; } return oneStep; }
- Time Complexity: O(n)
- Space Complexity: O(1)
5.2 Tiling Problems (2×n Board)
Problem:
Count ways to tile a 2×n board using 1×2 dominoes.
Observation:
- Place a vertical domino → reduces to 2×(n-1)
- Place two horizontal dominoes → reduces to 2×(n-2)
ways(n) = ways(n-1) + ways(n-2)
Java Solution:
public int tileBoard(int n) { if (n <= 1) return 1; int prev1 = 1, prev2 = 1; for (int i = 2; i <= n; i++) { int curr = prev1 + prev2; prev2 = prev1; prev1 = curr; } return prev1; }
- Time Complexity: O(n)
- Space Complexity: O(1)
5.3 Decode Ways (Dynamic Programming)
Problem:
Given a string of digits, count the number of ways to decode it where ‘A’ → 1, ‘B’ → 2, …, ‘Z’ → 26.
Observation:
- If the last digit forms a valid single number → add ways(n-1)
- If the last two digits form a number ≤26 → add ways(n-2)
Java Solution:
public int numDecodings(String s) { if (s == null || s.length() == 0) return 0; int n = s.length(); int prev2 = 1, prev1 = s.charAt(0) != '0' ? 1 : 0; for (int i = 1; i < n; i++) { int curr = 0; if (s.charAt(i) != '0') curr += prev1; int twoDigit = Integer.parseInt(s.substring(i-1, i+1)); if (twoDigit >= 10 && twoDigit <= 26) curr += prev2; prev2 = prev1; prev1 = curr; } return prev1; }
- Time Complexity: O(n)
- Space Complexity: O(1)
5.4 House Robber Problem (1D)
Problem:
Given an array of integers representing money in houses, find the maximum amount you can rob without robbing two adjacent houses.
Observation:
- Either rob current house → add value + max till house i-2
- Or skip current house → max till house i-1
rob(i) = max(rob(i-1), rob(i-2) + nums[i])
Java Solution:
public int rob(int[] nums) { if (nums.length == 0) return 0; if (nums.length == 1) return nums[0]; int prev2 = 0, prev1 = nums[0]; for (int i = 1; i < nums.length; i++) { int curr = Math.max(prev1, prev2 + nums[i]); prev2 = prev1; prev1 = curr; } return prev1; }
- Time Complexity: O(n)
- Space Complexity: O(1)
6. Key Takeaways
- Fibonacci is a classic DP pattern with recurrence and overlapping subproblems.
- Base recurrence:
F(n) = F(n-1) + F(n-2)
- Solutions: recursion, memoization, bottom-up DP, space optimization.
- Many problems reduce to Fibonacci-like patterns:
- Climbing stairs → counting sequences
- Tiling → placement problems
- Decode ways → sequence count with constraints
- House robber → optimal selection under adjacency constraint
- Recognize recurrence + base cases + overlapping subproblems → apply DP.