title: Climbing Stairs slug: climbing-stairs difficulty: easy leetcode_id: 70 leetcode_url: https://leetcode.com/problems/climbing-stairs/ categories: - dynamic-programming - math patterns: - dynamic-programming description: | You are climbing a staircase. It takes n steps to reach the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? constraints: | - 1 <= n <= 45 examples: - input: "n = 2" output: "2" explanation: "Two ways: (1+1) or (2)" - input: "n = 3" output: "3" explanation: "Three ways: (1+1+1), (1+2), (2+1)" explanation: approach: | 1. Recognize this follows the Fibonacci pattern 2. ways(n) = ways(n-1) + ways(n-2) 3. From step n-1, we can take 1 step to reach n 4. From step n-2, we can take 2 steps to reach n 5. Base cases: ways(1) = 1, ways(2) = 2 intuition: | At any step, you either got there by taking 1 step from the previous position or 2 steps from two positions back. This gives us the recurrence relation. This is essentially the Fibonacci sequence! The number of ways to reach step n equals the sum of ways to reach steps n-1 and n-2. common_pitfalls: - title: Using recursion without memoization description: | Naive recursion recalculates the same subproblems repeatedly, leading to exponential time complexity. Either use memoization or iterative DP. wrong_approach: "return climb(n-1) + climb(n-2) without caching" correct_approach: "Use bottom-up DP or memoize recursive calls" - title: Off-by-one in base cases description: | Carefully define base cases. There's 1 way to stay at ground (step 0), 1 way to reach step 1, and 2 ways to reach step 2. key_takeaways: - Many counting problems follow Fibonacci-like patterns - Convert recursion to iteration for O(1) space - Bottom-up DP avoids stack overflow for large inputs - Recognize overlapping subproblems as a DP signal time_complexity: "O(n)" space_complexity: "O(1)" complexity_explanation: | Time: We compute n states, each in O(1). Space: Only track two previous values (space-optimized DP). solutions: - approach_name: Space-Optimized DP (Optimal) is_optimal: true code: | def climb_stairs(n: int) -> int: if n <= 2: return n prev1, prev2 = 2, 1 for i in range(3, n + 1): current = prev1 + prev2 prev2 = prev1 prev1 = current return prev1 explanation: | Track only the two previous values since that's all we need. Equivalent to computing the nth Fibonacci number. - approach_name: Recursive with Memoization is_optimal: false code: | from functools import lru_cache def climb_stairs(n: int) -> int: @lru_cache(maxsize=None) def dp(step: int) -> int: if step <= 2: return step return dp(step - 1) + dp(step - 2) return dp(n) explanation: | Top-down approach with memoization. Uses O(n) space for the cache and recursion stack.