Start Learning
Javaneer
Back to stage
Stage 7·Recursion, Backtracking & DP

1D Dynamic Programming

The classic starter DPs - climbing stairs, house robber, coin change - and how to define a state and a transition.

16 min readAdvanced
On this page

The best way to get fluent at dynamic programming is to internalize a handful of 1D DP patterns - problems where the state is a single index and each answer depends on a few earlier ones. Climbing stairs, house robber, and coin change cover most of the shapes you'll meet.

Define the state, then the transition

Every DP is two decisions: what does dp[i] mean? (the state) and how does dp[i] depend on earlier entries? (the transition). Nail those two and the code writes itself.

House robber - maximize the loot from houses in a row, but you can't rob two adjacent houses:

// dp[i] = max loot from houses 0..i
int rob(int[] nums) {
    int prev2 = 0, prev1 = 0;                 // dp[i-2], dp[i-1]
    for (int money : nums) {
        int take = prev2 + money;             // rob this house (skip the previous)
        int skip = prev1;                     // don't rob it
        int curr = Math.max(take, skip);      // transition: best of the two choices
        prev2 = prev1; prev1 = curr;
    }
    return prev1;
}

The state is "best loot up to house i"; the transition is "either rob house i (adding it to the best from two houses back) or skip it (keeping the best from the previous house), take the max." Only the last two values matter, so it runs in O(1) space.

When the transition ranges over choices: coin change

Some transitions consider several options and take the best. Coin change - fewest coins to make an amount - defines dp[a] as the minimum coins for amount a, trying every coin as the last one:

// dp[a] = fewest coins to make amount a
int coinChange(int[] coins, int amount) {
    int[] dp = new int[amount + 1];
    Arrays.fill(dp, amount + 1);              // "infinity" sentinel
    dp[0] = 0;                                // base case: 0 coins for amount 0
    for (int a = 1; a <= amount; a++)
        for (int coin : coins)
            if (coin <= a)
                dp[a] = Math.min(dp[a], dp[a - coin] + 1);   // use this coin last
    return dp[amount] > amount ? -1 : dp[amount];
}

Here the transition loops over coins: dp[a] is one more than the best way to make a - coin, minimized over all coins. It's O(amount × coins).

The recipe

For any 1D DP: (1) define dp[i] in words; (2) write the transition - how dp[i] builds from smaller indices; (3) set the base case(s); (4) decide the iteration order so dependencies are ready; (5) optionally reduce space if only the last few entries are needed.

'Number of ways' vs. 'min/max' transitions

Two flavors of 1D DP transition. 'Count the ways' problems ADD subproblem answers (dp[i] = dp[i-1] + dp[i-2], like climbing stairs). 'Optimize' problems take a MIN or MAX over choices (dp[a] = min over coins). Spotting which kind you have tells you whether to sum or to take an extreme.

Filling in a ladder one rung at a time

1D DP is climbing a ladder where each rung's value is written using the rungs just below it. You never jump ahead - you fill rung 1, then rung 2 (using rung 1 and the base), then rung 3 (using 1 and 2), and so on, so every rung you need is already filled by the time you reach the next. The 'state' is what a rung's number means; the 'transition' is the little formula relating a rung to the ones beneath it. Build from the bottom and the top rung holds your answer.

Climbing stairs with variable steps

You can climb 1, 2, or 3 steps at a time. Count the distinct ways to reach step n. Define the state and transition, and give the base cases.

What are the two things you must define to write a 1D dynamic programming solution?

Key takeaways

  • 1D DP has a single-index state; define what dp[i] means, then the transition to smaller indices.
  • House robber: dp[i] = max(rob i + dp[i-2], skip i = dp[i-1]) - an optimize (max) transition, O(1) space.
  • Coin change: dp[a] = min over coins of dp[a-coin] + 1 - an optimize (min) transition looping over choices.
  • 'Count the ways' transitions ADD sub-answers (climbing stairs); 'optimize' transitions take a MIN/MAX.
  • Recipe: define state, write transition, set base cases, order the iteration, then reduce space if only recent entries matter.
Was this lesson helpful?
Edit this page on GitHub