70. Climbing Stairs
On LeetCode ->Reformulated question¶
Given n stairs, and each move can be 1 or 2 stairs, return how many different sequences of moves reach exactly the top.
Example:
Key trick¶
The last move to reach stair n is either:
- from
n - 1with a1-step - from
n - 2with a2-step
So:
\[
f(n) = f(n-1) + f(n-2)
\]
This is Fibonacci with shifted base cases.
Trap¶
- Counting paths by explicitly generating them is exponential and unnecessary.
- Wrong base cases break everything.
- Using recursion without memoization is too slow.
Why this question is interesting¶
- It is a tiny DP problem with a very clean recurrence.
- It tests whether you can turn "count all possibilities" into "count by last step".
Solution with idiomatic Python¶
class Solution:
def climbStairs(self, n: int) -> int:
# f(1) = 1, f(2) = 2
if n <= 2:
return n
# Keep only the last two values.
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
return b
There is no standard-library function that directly solves this exact problem more simply with the same asymptotic behavior, so the iterative DP above is the best direct answer.
Pytest test¶
import pytest
@pytest.mark.parametrize(
("n", "expected"),
[
(1, 1),
(2, 2),
(3, 3),
(4, 5),
(5, 8),
(6, 13),
(10, 89),
(45, 1836311903),
],
)
def test_climb_stairs(n, expected):
assert Solution().climbStairs(n) == expected
Comment my solution¶
- Your solution enumerates reachable positions level by level, which duplicates states many times.
- It works for small
n, but its time and memory are exponential. - The core observation is that only the number of ways to reach each stair matters, not the full list of paths.
ways_nbis indirect and harder to reason about than a recurrence on stair counts.
## Solution
class Solution:
def climbStairs(self, n: int) -> int:
ways_nb = 0
ways = [0] # start at floor 0
for _ in range(n + 1):
ways_new = []
for w in ways:
w1 = w + 1
w2 = w + 2
# we already are at the last floor
if w1 > n and w2 > n:
ways_nb += 1
if w1 <= n:
ways_new.append(w1)
if w2 <= n:
ways_new.append(w2)
ways = ways_new
return ways_nb
# new solution after reading AI comment on my first solution
class Solution:
def climbStairs(self, n: int) -> int:
# climbStairs(n) = climbStairs(n-2) + climbStairs(n-1)
if n == 1:
return 1
if n == 2:
return 2
return self.climbStairs(n-2) + self.climbStairs(n-1)
## Test
import pytest
@pytest.mark.parametrize(
"stairs_number, climbing_ways_number",
[(1,1), (2,2), (3,3), (4,5)]
)
def test_climbing_stairs(stairs_number, climbing_ways_number):
assert Solution().climbStairs(stairs_number) == climbing_ways_number
Code¶
import pytest
class Solution:
def climbStairs(self, n: int) -> int:
# Number of ways to reach stair n:
# ways(n) = ways(n - 1) + ways(n - 2)
# because the last move is either 1-step or 2-steps.
if n <= 2:
return n
a, b = 1, 2 # ways(1), ways(2)
for _ in range(3, n + 1):
a, b = b, a + b
return b
@pytest.mark.parametrize(
("n", "expected"),
[
(1, 1),
(2, 2),
(3, 3),
(4, 5),
(5, 8),
(6, 13),
(10, 89),
(45, 1836311903),
],
)
def test_climb_stairs(n, expected):
assert Solution().climbStairs(n) == expected
Solution().climbStairs(1) # 1
Solution().climbStairs(4) # 5
Solution().climbStairs(10) # 89