Overview
State-machine DP adds a small 'mode' to the DP state: for example, whether you currently hold a stock, whether you are in cooldown, or how many transactions you have used. At each step you compute the best value for every mode from the previous step's modes, following the allowed transitions between them.
The stock problems are the classic family. With modes hold and cash, today's hold = max(yesterday's hold, yesterday's cash - price), and today's cash = max(yesterday's cash, yesterday's hold + price). Adding cooldowns, fees, or transaction limits just adds modes or transitions.
A light can be green, yellow, or red, and only certain changes are allowed. To know the best outcome at time t for each color, you only need the best outcomes at time t - 1 for the colors that are allowed to change into it.
When to use it
- Rules depend on what you did previously: holding, cooldown, last action.
- A limited number of transactions or actions.
- Alternating or pattern constraints on sequences (last character type, parity).
- You can draw the problem as a few states with arrows labeled by actions.
Problem patterns it solves
Recognize it when: buy / sell with cooldown, fee, or k transactions.
- 122. Best Time to Buy and Sell Stock II
- 309. Best Time to Buy and Sell Stock with Cooldown
- 714. Best Time to Buy and Sell Stock with Transaction Fee
- 123. Best Time to Buy and Sell Stock III
- 188. Best Time to Buy and Sell Stock IV
Recognize it when: the next choice depends on the direction of the last one.
- 376. Wiggle Subsequence
- 1911. Maximum Alternating Subsequence Sum
Recognize it when: at most one change, deletion, or flip allowed.
- 1186. Maximum Subarray Sum with One Deletion
- 926. Flip String to Monotone Increasing
- 552. Student Attendance Record II
Recognize it when: adjacent items cannot share a color or pattern.
- 256. Paint House
- 265. Paint House II
- 1411. Number of Ways to Paint N x 3 Grid
Where it is used in real software
Strategies with holding periods, cooldowns, and transaction costs are modeled as state machines over time.
Hidden Markov models find the most likely sequence of hidden states with the Viterbi algorithm, which is state-machine DP.
Order lifecycles (pending, paid, shipped) and network protocols are state machines; optimizing over them is DP.
Viterbi decoding of convolutional codes in mobile networks is DP over encoder states.
Key terms
- Mode / state
- A small label describing the situation, such as hold or cash.
- Transition
- An allowed move between modes with its reward or cost.
- Viterbi
- State-machine DP for the most likely sequence of hidden states.
- Rolling states
- Keep only the previous step's value for each mode.
Designing a state machine DP
- 1List the modes
Stock with cooldown: hold, sold (just sold today), rest (free to buy).
- 2Draw the transitions
rest -> hold (buy), hold -> sold (sell), sold -> rest (cooldown), and each can stay.
- 3Write one equation per mode
hold = max(hold, rest - price); sold = hold + price; rest = max(rest, sold).
- 4Initialize
hold = -Infinity (cannot hold before buying), sold = -Infinity, rest = 0.
- 5Answer
The best among modes where you do not hold a stock: max(sold, rest).
Stock with cooldown on prices [1, 2, 3, 0, 2]
Use previous-day values when updating each mode
| Day | Price | hold | sold | rest |
|---|---|---|---|---|
| start | - | -inf | -inf | 0 |
| 0 | 1 | max(-inf, 0 - 1) = -1 | -inf | 0 |
| 1 | 2 | max(-1, 0 - 2) = -1 | -1 + 2 = 1 | max(0, -inf) = 0 |
| 2 | 3 | max(-1, 0 - 3) = -1 | -1 + 3 = 2 | max(0, 1) = 1 |
| 3 | 0 | max(-1, 1 - 0) = 1 | -1 + 0 = -1 | max(1, 2) = 2 |
| 4 | 2 | max(1, 2 - 2) = 1 | 1 + 2 = 3 | max(2, -1) = 2 |
NOWDay: start | Price: - | hold: -inf | sold: -inf | rest: 0
Answer max(sold, rest) = 3: buy at 1, sell at 2, cooldown, buy at 0, sell at 2. The cooldown is enforced because hold can only come from rest, never directly from sold.
Implementation
// 122. Unlimited transactionsfunction maxProfitII(prices) { let hold = -Infinity, cash = 0; for (const p of prices) { const prevHold = hold; hold = Math.max(hold, cash - p); cash = Math.max(cash, prevHold + p); } return cash;} // 309. With cooldownfunction maxProfitCooldown(prices) { let hold = -Infinity, sold = -Infinity, rest = 0; for (const p of prices) { const [h, s, r] = [hold, sold, rest]; hold = Math.max(h, r - p); // buy only from rest sold = h + p; // sell today rest = Math.max(r, s); // cooldown passes } return Math.max(sold, rest);} // 714. With transaction feefunction maxProfitFee(prices, fee) { let hold = -prices[0], cash = 0; for (const p of prices.slice(1)) { hold = Math.max(hold, cash - p); cash = Math.max(cash, hold + p - fee); } return cash;} // 188. At most k transactions: modes per transaction countfunction maxProfitK(k, prices) { const buy = new Array(k + 1).fill(-Infinity); const sell = new Array(k + 1).fill(0); for (const p of prices) { for (let t = 1; t <= k; t++) { buy[t] = Math.max(buy[t], sell[t - 1] - p); sell[t] = Math.max(sell[t], buy[t] + p); } } return sell[k];}Complexity and performance
Constant modes: O(n).
Two modes per transaction count.
Rolling values per mode.
Trade-offs
Stock II also has a greedy solution (sum every positive daily difference). The state machine generalizes to cooldowns and fees where greedy is harder to prove.
Use previous-step values (copy them first) or order the updates carefully, otherwise one mode reads another mode's already-updated value.
Variants and related techniques
Maximize probability over hidden states with transition and emission scores.
When the mode is a set (visited cities, used items), the state becomes a bitmask (TSP DP).
Count strings avoiding a pattern by DP over KMP automaton states.
Common mistakes
- Reading an already-updated mode in the same step.
Fix: Save previous values before computing the new ones.
- Initializing hold to 0.
Fix: Holding a stock before buying is impossible: use -Infinity (or -prices[0]).
- k larger than n / 2 in the k-transactions problem.
Fix: Then it equals unlimited transactions; switch to the O(n) version to avoid huge loops.
Interview questions
How do you model the stock cooldown problem?
Three modes: holding, just sold, and resting. Buying is only allowed from resting, so after selling you must pass through resting for a day, which enforces the cooldown.
How do you recognize a state machine DP?
The allowed action at step i depends on a small amount of history (holding or not, last direction, count used). Encode that history as a mode and keep one best value per mode.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 122. Best Time to Buy and Sell Stock II | Medium | Two modes. |
| 309. Best Time to Buy and Sell Stock with Cooldown | Medium | Three modes. |
| 714. Best Time to Buy and Sell Stock with Transaction Fee | Medium | Cost on transition. |
| 376. Wiggle Subsequence | Medium | Direction modes. |
| 926. Flip String to Monotone Increasing | Medium | Ending modes. |
| 188. Best Time to Buy and Sell Stock IV | Hard | Transactions as a dimension. |