Files
leetcode/docs/(algorithms)/dynamic-programming.mdx
T

128 lines
3.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Dynamic Programming (1-D)
---
# Dynamic Programming (1-D)
## The idea
DP is backtracking with a memory.
Backtracking tries every path. Many paths repeat the same subproblem.
DP solves each subproblem **once**, saves the answer, and reuses it.
Grokking's rule: break the big problem into small problems.
Solve the small ones first. Build up.
**The two things you must find:**
1. **The state** — what does `dp[i]` mean, in one sentence?
2. **The recurrence** — how does `dp[i]` come from earlier answers?
## The picture — why memo matters (Climbing Stairs)
Without memo, `f(5)` computes `f(3)` twice and `f(2)` three times:
```mermaid
flowchart TD
A["f(5)"] --> B["f(4)"]
A --> C["f(3)"]
B --> D["f(3)"]
B --> E["f(2)"]
C --> F["f(2)"]
C --> G["f(1)"]
D --> H["f(2)"]
D --> I["f(1)"]
style C fill:#c62828,color:#fff
style D fill:#c62828,color:#fff
style E fill:#ef6c00,color:#fff
style F fill:#ef6c00,color:#fff
style H fill:#ef6c00,color:#fff
```
Red and orange = repeated work. Memo turns the tree into a straight line: O(2ⁿ) → O(n).
## Climbing Stairs (LC 70)
State: `dp[i]` = ways to reach step i.
Recurrence: you arrive from one step below or two below.
```python
def climb_stairs(n: int) -> int:
if n <= 2:
return n
prev2, prev1 = 1, 2
for _ in range(3, n + 1):
prev2, prev1 = prev1, prev1 + prev2
return prev1
```
## House Robber (LC 198)
State: `dp[i]` = max loot using houses 0..i.
Recurrence at each house: **rob it** (skip the neighbor) or **skip it**.
```mermaid
flowchart LR
A["House i"] --> B["Rob:<br/>nums[i] + dp[i-2]"]
A --> C["Skip:<br/>dp[i-1]"]
B --> D["dp[i] = max of both"]
C --> D
style D fill:#2e7d32,color:#fff
```
```python
def rob(nums: list[int]) -> int:
skip = take = 0
for n in nums:
skip, take = max(skip, take), skip + n # skip it / rob it
return max(skip, take)
```
## Coin Change (LC 322)
State: `dp[a]` = fewest coins to make amount a.
Recurrence: try each coin, take the best.
```python
import math
def coin_change(coins: list[int], amount: int) -> int:
dp = [math.inf] * (amount + 1)
dp[0] = 0
for a in range(1, amount + 1):
for c in coins:
if c <= a:
dp[a] = min(dp[a], dp[a - c] + 1)
return dp[amount] if dp[amount] != math.inf else -1
```
## The interview script
Say these four lines out loud, in order:
1. "The brute force is backtracking — try everything."
2. "Subproblems overlap, so I will memoize."
3. "State: dp[i] means ___." (one sentence)
4. "Recurrence: dp[i] = ___."
## Complexity
| | Time | Space |
|---|---|---|
| Climbing Stairs / House Robber | O(n) | O(1) with rolling vars |
| Coin Change | O(amount × coins) | O(amount) |
## Close-out ritual
Before you submit, say out loud:
1. Time and space complexity.
2. One edge case trace: n = 0 or 1, empty array, or unreachable amount (return -1).
## Plan problems
**A-set:** LC 70 · 746 · 198 · 213 · 322 · 300
**B-set:** LC 139 · 91 · 647
Note: DP matters only if Google or Databricks advance to later rounds. Your fintech targets skew toward simulation, hashmap, and heap.