Framework Thinking - Neetcode 150 - Count Ways of Climbing Stairs

Here is solutions for Climbing Stairs.

1. Understand the problem

  • You are standing at the bottom of a staircase with n steps.

  • Each time, you can climb:

    • 1 step, or

    • 2 steps

  • Your task is to return the total number of distinct ways to reach step n.

2. Clarify constraints, asks 4 - 5 questions including edge cases.

1.What is the range of n?

  • LeetCode: 1 ≤ n ≤ 45
  1. Can n = 0?
  • Usually no in LeetCode, but mathematically it would be 1 way (do nothing).
  1. Are we allowed to take jumps larger than 2?
  • ❌ No, only {1, 2}.
  1. Do different orders count as different ways?
  • ✅ Yes. (1+2 and 2+1 are different)
  1. Do we need the actual paths or just the count?
  • ✅ Only the count.

3. Explore examples.

  1. Example 1
n = 1
Ways: [1]
Output = 1
  1. Example 2
n = 2
Ways: [1+1], [2]
Output = 2
  1. Example 3
n = 3
Ways:
1 + 1 + 1
1 + 2
2 + 1
Output = 3

4. Brainstorm 2 - 3 solutions, naive solution first and optimize later. Explain the key idea of each solution.

4.1. Solution 1: Naive Recursion (Exponential) - Time O(2^N), Space O(N)

f(n) = f(n-1) + f(n-2)
def climbStairs(n):
    if n <= 2:
        return n
    return climbStairs(n-1) + climbStairs(n-2)

  • Time: O(2^N)

  • Space: O(N)

4.2. Solution 2: Precomputed DP - Time O(N), Space O(N)

dp[i] = number of ways to reach step i
dp[i] = dp[i-1] + dp[i-2]
  • Time: O(N)

  • Space: O(N)

4.3. Space-Optimized DP - Using only prev1, prev2 - Time O(N), Space O(1)

def climbStairs(n):
    if n <= 2:
        return n

    prev2 = 1   # dp[1]
    prev1 = 2   # dp[2]

    for i in range(3, n + 1):
        cur = prev1 + prev2
        prev2 = prev1
        prev1 = cur

    return prev1

  • Time: O(N)

  • Space: O(1)

5. Implement solutions.

5.1. Recursion - Time O(2^N), Space O(N)

class Solution:
    def climbStairs(self, n: int) -> int:

        def dfs(i):
            if i >= n:
                return i == n
            return dfs(i + 1) + dfs(i + 2)

        return dfs(0)
  • Time: O(2^N)

  • Space: O(N)

5.2. Caching DP - Top-down - Time O(N), Space O(N)

class Solution:
    def climbStairs(self, n: int) -> int:
        cache = [-1] * n
        def dfs(i):
            if i >= n:
                return i == n
            if cache[i] != -1:
                return cache[i]
            cache[i] = dfs(i + 1) + dfs(i + 2)
            return cache[i]

        return dfs(0)
  • Time: O(N)

  • Space: O(N)

5.3. Bottom-up DP - Build O(N) from Index 0 - Time O(N), Space O(N)

class Solution:
    def climbStairs(self, n: int) -> int:
        if n <= 2:
            return n
        dp = [0] * (n + 1)
        dp[1], dp[2] = 1, 2
        for i in range(3, n + 1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[n]
  • Time: O(N)

  • Space: O(N)

5.4. Dynamic Programming (Space Optimized) - Time O(N), Space O(1)

class Solution:
    def climbStairs(self, n: int) -> int:
        one, two = 1, 1

        for i in range(n - 1):
            temp = one
            one = one + two
            two = temp

        return one
  • Time: O(N)

  • Space: O(1)

5.5. Math - Time O(1), Space O(1)

class Solution:
    def climbStairs(self, n: int) -> int:
        sqrt5 = math.sqrt(5)
        phi = (1 + sqrt5) / 2
        psi = (1 - sqrt5) / 2
        n += 1
        return round((phi**n - psi**n) / sqrt5)
  • Time: O(1)

  • Space: O(1)

6. Dry run testcases.

prev2 = 1   # ways to reach step 1
prev1 = 2   # ways to reach step 2
cur = prev1 + prev2
cur = 3 + 2 = 5
December 6, 2025