The problem
You are at the bottom of a staircase with n steps. Each move climbs either 1 step or 2 steps. Return how many different sequences of moves take you exactly to the top. The input is a single integer n (at least 1).
Input: n = 5
Output: 8There are 8 orderings of 1s and 2s that add up to 5, for example 1+1+1+1+1, 2+2+1, 1+2+2 and 2+1+2.
How to think about it
Start with brute force. Recursively try both moves from every step: ways(n) = ways(n-1) + ways(n-2), with a direct recursive call for each. It is correct, but the call tree doubles at each level, so it is O(2ⁿ). ways(3) gets recomputed again and again from different branches.
The key insight: look at the last move. Every way to reach step n ends with either a 1-step (from n-1) or a 2-step (from n-2). Those two groups don’t overlap and together cover everything, so ways[n] = ways[n-1] + ways[n-2]. That is the Fibonacci recurrence, with ways[0] = 1 (one way to stand still) and ways[1] = 1.
Only two values matter. Each answer depends on the previous two and nothing older. So instead of a whole table, keep two rolling variables and slide them forward n times. That turns exponential recursion into a single O(n) loop with O(1) memory.
Which pattern is this? 1-D dynamic programming. The tell is “count the ways” where each choice moves you a small fixed distance, so the answer for n is built from the answers just below it.
Approach
- Let
a = ways[0] = 1andb = ways[1] = 1. - Repeat
ntimes: shift the window forward witha, b = b, a + b. - After
ishifts,aholdsways[i]. Afternshifts, returna.
Solution
def climb_stairs(n):
a, b = 1, 1 # ways[0], ways[1]
for _ in range(n): a, b = b, a + b # slide: ways[i] = ways[i-1] + ways[i-2]
return a
# climb_stairs(5) -> 8Dry run
For n = 5, the values after each pass of the loop:
| Pass | a (= ways[pass]) |
b (= ways[pass+1]) |
|---|---|---|
| start | 1 | 1 |
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 3 | 5 |
| 4 | 5 | 8 |
| 5 | 8 | 13 |
After 5 passes a = 8, so the answer is 8.
Complexity
- Time: O(n). The loop runs
ntimes and does constant work each time. - Space: O(1). Only two integers are stored, no matter how large
nis.
Edge cases and pitfalls
n = 1returns 1 andn = 2returns 2; both fall out of the loop with no special case.- Off-by-one in the base case. Starting from
ways[1] = 1, ways[2] = 2is also fine, but then the loop count changes. Pick one convention and tracen = 1to check it. - Plain recursion without memoisation times out around
n = 40. If you write it top-down, add@lru_cache. - Big numbers. Python integers don’t overflow; in Java or C++ the count for large
nwould need a 64-bit type.
Related problems
- Min Cost Climbing Stairs (LeetCode 746): the same two-predecessor shape, but minimising cost instead of counting.
- Decode Ways (LeetCode 91): Climbing Stairs where each 1-step or 2-step is only allowed if the digits are valid.
- House Robber (LeetCode 198): another “look at the last choice” recurrence with two rolling variables.
- 1.Climbing Stairs (LeetCode 70)
- 2.Min Cost Climbing Stairs (LeetCode 746)
- 3.Maximum Subarray (LeetCode 53)
- 4.House Robber (LeetCode 198)
- 5.House Robber II (LeetCode 213)
- 6.Jump Game (LeetCode 55)
- 7.Coin Change (LeetCode 322)
- 8.Coin Change II (LeetCode 518)
- 9.Word Break (LeetCode 139)
- 10.Decode Ways (LeetCode 91)
- 11.Maximum Product Subarray (LeetCode 152)
- 12.Longest Increasing Subsequence (LeetCode 300)
- 13.Partition Equal Subset Sum (LeetCode 416)