Skip to content

70. Climbing Stairs (Easy)

Problem

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

Example

  • n = 22 (1+1, 2)
  • n = 33 (1+1+1, 1+2, 2+1)

LeetCode 70 · Link · Easy

Try it yourself

idle

Starter code: this editor begins with intentional TODOs. Fill the function, run the embedded tests, then compare your solution with the worked approaches below.

Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Approach 1: Brute force, naive recursion

f(n) = f(n-1) + f(n-2).

def climb_stairs(n):
if n <= 2: # L1: base case
return n
return climb_stairs(n - 1) + climb_stairs(n - 2) # L2: two recursive calls per step

Where the time goes, line by line

Variables: n = the input integer (number of stairs).

LinePer-call costTimes executedContribution
L1 (base case)O(1)O(1)O(2n)O(2ⁿ) leavesO(2n)O(2ⁿ)
L2 (two recursive calls)O(1)O(1) + subtree costO(2n)O(2ⁿ) nodesO(2n)O(2ⁿ) ← dominates

Each call at depth d spawns two more calls, doubling the tree width. The total node count is the Fibonacci-tree size, which grows as O(2n)O(2ⁿ).

Complexity

  • Time: O(2n)O(2ⁿ), driven by L2. Exponential, same call tree as Fibonacci.
  • Space: O(n)O(n) recursion stack depth.

Approach 2: Top-down with memoization

Cache results by n.

from functools import lru_cache
@lru_cache(maxsize=None)
def climb_stairs(n):
if n <= 2: # L1: base case
return n
return climb_stairs(n - 1) + climb_stairs(n - 2) # L2: two sub-calls, result cached

Where the time goes, line by line

Variables: n = the input integer (number of stairs).

LinePer-call costTimes executedContribution
L1 (base case)O(1)O(1)2O(1)O(1)
L2 (cached sub-calls)O(1)O(1) eachn - 2 unique statesO(n)O(n) ← dominates

Each unique n is computed once and cached. After that, every subsequent call hits the cache in O(1)O(1). The total unique states is n, so all work is O(n)O(n).

Complexity

  • Time: O(n)O(n), driven by L2 (n unique states, each computed once).
  • Space: O(n)O(n) cache + recursion stack.

Try this approach:

idle
Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Approach 3: Bottom-up DP array

Build the full Fibonacci sequence in a dp array, one cell per step.

def climb_stairs(n):
if n <= 2: # L1: base case
return n
dp = [0] * (n + 1) # L2: O(n) allocation
dp[1], dp[2] = 1, 2 # L3: seed base cases
for i in range(3, n + 1): # L4: loop n-2 times
dp[i] = dp[i - 1] + dp[i - 2] # L5: O(1) recurrence
return dp[n] # L6: O(1) return

Where the time goes, line by line

Variables: n = the input integer.

LinePer-call costTimes executedContribution
L2 (allocate dp)O(n)O(n)1O(n)O(n)
L3 (seed)O(1)O(1)1O(1)O(1)
L4, L5 (loop + recurrence)O(1)O(1)n - 2O(n)O(n) ← dominates
L6 (return)O(1)O(1)1O(1)O(1)

Complexity

  • Time: O(n)O(n), driven by L4/L5 (n - 2 iterations).
  • Space: O(n)O(n) for the dp array.

Try this approach:

idle
Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Approach 4: Bottom-up with two variables (optimal)

Only the last two values are needed.

def climb_stairs(n):
if n <= 2: # L1: base case O(1)
return n
a, b = 1, 2 # L2: init f(1), f(2)
for _ in range(3, n + 1): # L3: loop runs n-2 times
a, b = b, a + b # L4: O(1) update per iteration
return b

Where the time goes, line by line

Variables: n = the input integer (number of stairs).

LinePer-call costTimes executedContribution
L1 (base check)O(1)O(1)1O(1)O(1)
L2 (init)O(1)O(1)1O(1)O(1)
L3 (loop)O(1)O(1)n - 2O(n)O(n) ← dominates
L4 (update)O(1)O(1)n - 2O(n)O(n)

The loop runs exactly n - 2 times; each iteration is a fixed-cost swap-and-add. Nothing allocates.

Complexity

  • Time: O(n)O(n), driven by L3/L4 (n - 2 iterations).
  • Space: O(1)O(1), just two scalars.

Try this approach:

idle
Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Summary

ApproachTimeSpace
Naive recursionO(2n)O(2ⁿ)O(n)O(n)
Memoized recursionO(n)O(n)O(n)O(n)
Bottom-up, dp arrayO(n)O(n)O(n)O(n)
Bottom-up, two varsO(n)O(n)O(1)O(1)

Template for every Fibonacci-shape DP (House Robber, Min Cost Climbing Stairs, Tribonacci, etc.).

Test cases

# Quick smoke tests, paste into a REPL or save as test_climbing_stairs.py and run.
# Uses the canonical implementation (Approach 4: bottom-up two variables).
def climb_stairs(n):
if n <= 2:
return n
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
return b
def _run_tests():
assert climb_stairs(1) == 1 # single step: one way
assert climb_stairs(2) == 2 # (1+1) or (2): two ways
assert climb_stairs(3) == 3 # (1+1+1),(1+2),(2+1): three ways
assert climb_stairs(4) == 5
assert climb_stairs(5) == 8
assert climb_stairs(10) == 89
print("all tests pass")
if __name__ == "__main__":
_run_tests()
  • Arrays, conceptual DP array (here collapsed to two scalars)
  • Tabulation, the bottom up table fill that solves dependencies in a reliable order.
  • Dynamic Programming, the state and transition model for reusing answers to overlapping subproblems.