Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Designing States and Transitions

โญ beginnerโณ 16 min read๐Ÿ“ Lesson 44 of 281

Three classic designs โ€” counting paths, min-cost, take-or-skip โ€” cover half of beginner DP.

Design 1 โ€” counting: stairs

"How many ways to climb n stairs taking 1 or 2 steps?" State: dp[i] = number of ways to reach step i. Last move was from i-1 (one step) or i-2 (two steps), so:

dp[0] = 1; dp[1] = 1;
for (int i = 2; i <= n; ++i) dp[i] = dp[i-1] + dp[i-2];

Same recurrence as Fibonacci โ€” recognizing that is a competition skill: many problems ARE fib in disguise.

Design 2 โ€” min-cost: coin change

Fewest coins summing to S with coin values c1..ck. State: dp[s] = min coins to make sum s. Transition: try every coin as the last one:

dp[0] = 0;                            // zero coins make zero
for (int s = 1; s <= S; ++s) {
    dp[s] = INF;
    for (int c : coins)
        if (c <= s) dp[s] = min(dp[s], dp[s-c] + 1);
}

Unreachable sums stay INF โ€” printing dp[S] when it is still INF is a real bug (print -1 or "impossible" per the statement).

Design 3 โ€” take-or-skip: 0/1 knapsack

Items with weight w[i], value v[i], capacity W. State: dp[i][cap] = best value using the first i items with capacity cap. The i-th item is skipped (dp[i-1][cap]) or taken (dp[i-1][cap-w[i]] + v[i]):

for (int i = 1; i <= n; ++i)
  for (int cap = 0; cap <= W; ++cap) {
    dp[i][cap] = dp[i-1][cap];
    if (w[i] <= cap)
        dp[i][cap] = max(dp[i][cap], dp[i-1][cap-w[i]] + v[i]);
  }

Note the loop direction: 2D knapsack reads row i-1, so any direction works. The 1D memory-saving form (for cap: W..w[i], descending) is the classic interview trap โ€” ascending would allow taking an item twice. Beginner rule: 2D first, optimize later.

โšก Now practice

Ready to Code
Dynamic Programming Problem SetFibonacci tables, stair counting, coin change, knapsack, and run-length DP.
5 challenges ยท ยท ~50 min