LeetCode ยท #70

Climbing Stairs Solution

You are climbing a staircase with n steps. Each time you can climb 1 or 2 steps. Return the number of distinct ways to reach the top.

01
Section One ยท Problem

Problem Statement

๐Ÿท๏ธ

Difficulty

Easy

๐Ÿ”—

LeetCode

Problem #70

๐Ÿ—๏ธ

Pattern

DP โ€” 1D Fibonacci recurrence

You are climbing a staircase. It takes n steps to reach the top. Each time you can climb either 1 or 2 steps. In how many distinct ways can you climb to the top?

Example
Input: n = 3 Output: 3 // 1+1+1, 1+2, 2+1 โ€” three distinct ways
Constraints
โ€ข 1 โ‰ค n โ‰ค 45 โ† fits in int; O(n) required, O(2โฟ) TLE
02
Section Two ยท Approach 1

Recursion โ€” O(2โฟ)

At each step, you have two choices: climb 1 or climb 2. Recursively count all paths: ways(n) = ways(n-1) + ways(n-2). Base cases: ways(0)=1, ways(1)=1.

Why it works

The recurrence correctly partitions all paths by the first move: paths that start with a 1-step + paths that start with a 2-step. Base cases represent "already at the top" (1 way).

Why we can do better
Problem: The recursion tree branches exponentially โ€” ways(n) recomputes ways(n-2) twice, ways(n-3) three times, etc. Total calls: O(2โฟ). For n=45 that's ~35 billion calls. Memoization or bottom-up DP brings this to O(n) by storing each subproblem once.
Java โ€” Naive recursion
class Solution { public int climbStairs(int n) { if (n <= 1) return 1; return climbStairs(n - 1) + climbStairs(n - 2); // O(2โฟ) calls } }
Python โ€” Naive recursion
class Solution: def climbStairs(self, n: int) -> int: if n <= 1: return 1 return self.climbStairs(n-1) + self.climbStairs(n-2)
MetricValue
TimeO(2โฟ) โ€” exponential recursion tree
SpaceO(n) โ€” recursion depth
03
Section Three ยท Approach 2

Bottom-Up DP / Fibonacci โ€” O(n) time, O(1) space

The recurrence dp[i] = dp[i-1] + dp[i-2] is exactly the Fibonacci sequence. Since each state depends only on the previous two, we only need two variables โ€” no array required.

๐Ÿ’ก Mental model: Imagine you're standing on a staircase and looking down. The number of ways to reach your current step equals "ways if I got here with a 1-step" plus "ways if I got here with a 2-step." That's just the ways to reach the step below me plus the step two below me. You only need to remember the last two answers as you walk up โ€” like a caterpillar inching forward with two legs, always dropping the back leg and growing a new front one.
Algorithm โ€” two-variable Fibonacci
  • Initialize a = 1 (ways to step 0), b = 1 (ways to step 1).
  • For i from 2 to n: temp = a + b; a = b; b = temp.
  • Return b โ€” the number of ways to reach step n.
๐ŸŽฏ When to recognize this pattern:
  • Any time dp[i] depends on a fixed number of previous states, you can reduce O(n) space to O(1) by keeping only those states in variables.
  • This "rolling variables" optimization applies to LC 198 (House Robber), LC 746 (Min Cost Climbing Stairs), and any Fibonacci-like recurrence.
  • The signal: "dp[i] = f(dp[i-1], dp[i-2])."
Why this is Fibonacci and not combinatorics:
  • You might try to count paths using C(n,k) combinations, but the number of 2-steps k can range from 0 to โŒŠn/2โŒ‹, and each k gives C(n-k, k) arrangements.
  • Summing these is more complex and error-prone than the DP approach.
  • The Fibonacci recurrence subsumes all these cases automatically.
04
Section Four ยท Trace

Visual Walkthrough

Trace for n = 5. Building dp bottom-up with two variables.

Climbing Stairs โ€” Fibonacci DP (n=5)
dp[i] = dp[i-1] + dp[i-2]. Only two variables needed: a (prev-prev), b (prev). Step: 0 1 2 3 4 5 Ways: 1 1 2 3 5 8 Init: a=1 (step 0), b=1 (step 1) i=2: b = a + b = 1+1 = 2. a โ† old b = 1. Now a=1, b=2. i=3: b = a + b = 1+2 = 3. a โ† old b = 2. Now a=2, b=3. i=4: b = a + b = 2+3 = 5. a โ† old b = 3. Now a=3, b=5. i=5: b = a + b = 3+5 = 8. a โ† old b = 5. Now a=5, b=8. return b = 8 โœ“
05
Section Five ยท Implementation

Code โ€” Java & Python

Java โ€” Two-variable Fibonacci
class Solution { public int climbStairs(int n) { int a = 1, b = 1; // dp[0]=1, dp[1]=1 for (int i = 2; i <= n; i++) { int tmp = a + b; // dp[i] = dp[i-2] + dp[i-1] a = b; // slide window forward b = tmp; } return b; } }
Python โ€” Two-variable Fibonacci
class Solution: def climbStairs(self, n: int) -> int: a, b = 1, 1 # dp[0], dp[1] for _ in range(2, n + 1): a, b = b, a + b # simultaneous swap โ€” no temp needed return b
06
Section Six ยท Analysis

Complexity Analysis

ApproachTimeSpaceTrade-off
Naive recursionO(2โฟ)O(n)Exponential โ€” TLE at n โ‰ฅ ~30
Memoized recursionO(n)O(n)Top-down DP array; correct but uses O(n) space
Two-variable Fibonacci โ† optimal O(n) O(1) Only two variables; minimal code; constant space
Can we do better than O(n)?:
  • Yes โ€” matrix exponentiation gives O(log n) by raising the Fibonacci transformation matrix to the nth power.
  • But for n โ‰ค 45, the constant-factor overhead of matrix multiplication makes O(n) faster in practice.
  • The O(log n) approach is academic โ€” interviewers rarely expect it.
07
Section Seven ยท Edge Cases

Edge Cases & Pitfalls

CaseInputWhy It Matters
n = 11Only one step โ€” one way. Loop doesn't execute. Return b=1.
n = 22Two ways: 1+1 or 2. One loop iteration. b=2.
n = 0Not in constraintsConstraints say n โ‰ฅ 1. But if allowed, answer is 1 (already at top).
n = 45 (max)45Fib(46) = 1,836,311,903 โ€” fits in int (max ~2.1 billion). No overflow.
Off-by-one in loopanyLoop must run from 2 to n (inclusive). Running to n-1 gives dp[n-1] instead of dp[n].
Swapping order wronganyIf you update a before computing a+b, the sum uses the wrong (already updated) a value.
โš  Common Mistake: Writing a = b; b = a + b; instead of using a temp variable (Java) or simultaneous swap (Python). The first line overwrites a with b, and then the second line computes b + b instead of old_a + b. In Java, use int tmp = a+b; a = b; b = tmp;. In Python, use a, b = b, a+b โ€” the right side is fully evaluated before assignment.

โ† Back to DP โ€” 1D problems