150NeetCode 150

99.Climbing Stairs

EasyBlind 751-D Dynamic Programming ยท 1/12

Problem

You are climbing a staircase that has n steps. Each move you can climb either 1 step or 2 steps.

Return the number of distinct ways to reach the top (step n) starting from the ground (step 0). Two ways are different if the sequence of 1s and 2s is different.

Examples

Input:  n = 2
Output: 2
Explanation: 1 + 1, or 2.
Input:  n = 3
Output: 3
Explanation: 1 + 1 + 1, 1 + 2, 2 + 1.
Input:  n = 5
Output: 8
Explanation: The answers for n = 1, 2, 3, 4, 5 are 1, 2, 3, 5, 8 โ€” the Fibonacci sequence.

Constraints

  • 1 <= n <= 45

๐Ÿ’ก Key Insight

The last move onto step i was either a 1-step from i - 1 or a 2-step from i - 2, and these two groups never overlap. So ways(i) = ways(i - 1) + ways(i - 2) with ways(0) = 1 and ways(1) = 1 โ€” exactly Fibonacci. Plain recursion recomputes the same ways(k) exponentially many times; caching or building bottom-up makes it linear, and since each value only needs the previous two, two variables are enough.

Recursion (Brute Force)

TimeO(2โฟ)SpaceO(n)

Intuition

Stand on step i. To get here you must have come from i - 1 (one step) or i - 2 (two steps). Count the ways to reach each of those and add them. Recurse until you hit the base cases.

Recurrence: f(i) = f(i - 1) + f(i - 2), with f(0) = 1 (one way to stand still at the bottom) and f(1) = 1.

Algorithm

  1. If n <= 1, return 1.
  2. Otherwise return climbStairs(n - 1) + climbStairs(n - 2).

Visualization

The recursion tree for n = 5. Notice f(3) is computed twice and f(2) three times โ€” that duplicated work is what makes this exponential.

flowchart TD
    A["f(5)"] --> B["f(4)"]
    A --> C["f(3)"]
    B --> D["f(3)"]
    B --> E["f(2)"]
    C --> F["f(2)"]
    C --> G["f(1) = 1"]
    D --> H["f(2)"]
    D --> I["f(1) = 1"]
    E --> J["f(1) = 1"]
    E --> K["f(0) = 1"]
    F --> L["f(1) = 1"]
    F --> M["f(0) = 1"]

Code

java
class Solution {
    public int climbStairs(int n) {
        // base cases: one way to be at step 0 or step 1
        if (n <= 1) {
            return 1;
        }
        // last move was either a 1-step or a 2-step
        return climbStairs(n - 1) + climbStairs(n - 2);
    }
}

Complexity

  • Time: O(2โฟ) โ€” each call branches into two (more precisely O(ฯ†โฟ) โ‰ˆ O(1.618โฟ)); n = 45 will time out.
  • Space: O(n) โ€” maximum recursion depth.

Complexity Comparison

Approach Time Space
Recursion (Brute Force) O(2โฟ) O(n)
Top-Down Memoization O(n) O(n)
Bottom-Up Tabulation O(n) O(n)
Space-Optimized DP O(n) O(1)

Common Pitfalls

  • Setting f(0) = 0: there is exactly one way to "climb" zero steps (do nothing), and f(2) = f(1) + f(0) must equal 2.
  • Allocating new int[n + 1] and then writing dp[2] when n = 1 โ€” guard the base case or start the loop correctly.
  • Plain recursion without memoization times out long before n = 45.
  • Overflow is not a concern here (f(45) = 1,836,311,903 fits in int), but the same pattern with larger n needs long.