원클릭으로
algo-dp
Dynamic programming — state design, memoization vs tabulation, dimension-reduction, and when DP is the wrong tool.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Dynamic programming — state design, memoization vs tabulation, dimension-reduction, and when DP is the wrong tool.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Breadth-first search — shortest path on unweighted graphs, level-order traversal, and the `visited` discipline that prevents O(2^n) blowups.
Binary search invariants, half-open intervals, and the `lo<hi` template that beats off-by-one bugs.
Depth-first search — recursive vs iterative, recursion-depth gotchas, three-color cycle detection, topological sort.
Pick the right traversal — BFS for unweighted shortest path, Dijkstra for weighted, A* for goal-directed, 0/1-BFS for binary weights.
Greedy algorithms — exchange-argument proofs, when greedy beats DP, classic patterns (interval scheduling, Huffman, scheduling).
Hash maps and sets — when O(1) lookup pays off, hash collisions, frozen keys, and hashing custom types.
| name | algo-dp |
| description | Dynamic programming — state design, memoization vs tabulation, dimension-reduction, and when DP is the wrong tool. |
| when-to-use | Optimal-substructure problems with overlapping subproblems: knapsack, edit distance, LIS, coin change, interval DP, bitmask DP. |
DP fails most often at the design phase, not the coding phase. If
you can name state, transition, and base case in one sentence
each, the implementation usually writes itself.
n is built
from optimal answers to strictly smaller subproblems.dp[s] is the answer to subproblem s. The order
of filling matters: every dependency of dp[s] must already be
computed.O(states × transitions). A 1D DP over n with O(1)
transition is O(n); a 2D DP over n × m with O(k) transition
is O(n m k).from functools import cache
def edit_distance(s: str, t: str) -> int:
"""Minimum insert/delete/replace ops to convert s into t."""
@cache
def f(i: int, j: int) -> int:
if i == len(s): return len(t) - j
if j == len(t): return len(s) - i
if s[i] == t[j]: return f(i + 1, j + 1)
return 1 + min(
f(i + 1, j), # delete s[i]
f(i, j + 1), # insert t[j]
f(i + 1, j + 1), # replace
)
return f(0, 0)
@cache is the cheapest way to add memoization in Python and turns
a 2^n recursion into O(nm). For very tight memory budgets,
convert to a bottom-up table.
// 0/1 knapsack: max value with weight <= W.
function knapsack(weights, values, W) {
let dp = new Array(W + 1).fill(0);
for (let i = 0; i < weights.length; i++) {
// Iterate w downward so each item is used at most once.
for (let w = W; w >= weights[i]; w--) {
dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
}
}
return dp[W];
}
Reducing 2D to 1D by reusing the previous row is the most common DP optimisation. The downward-iteration trick prevents using the current item more than once (vs unbounded knapsack, which iterates upward).
(i, j, k, mask, ...), count
them up before coding. n=100, mask=2^20 is 100M states — almost
certainly too big.sys.setrecursionlimit(10**6) early in the run, or rewrite
bottom-up.argmax.W == sum(weights),
W == 0).s == t, s == "", t == "".When you cannot describe the state in one sentence, you are not ready to write the recurrence. Stop and re-decompose.