mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
127 lines
3.1 KiB
Plaintext
127 lines
3.1 KiB
Plaintext
---
|
||||
|
|
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.
|