1-D Dynamic Programming
Solve a problem over a line of positions by building each position's answer from a handful of earlier answers, usually in O(n) time and O(1) space.
Instinct The best answer at position i depends only on a few earlier positions (i-1, i-2, ...) - write dp[i] from its predecessors, then roll it into variables.
Memory hack Look back, pick best, roll forward - every step only remembers the last couple of stairs it stood on.
At a glance
When to use it
- The input is a single line of positions such as stairs, houses, days or array cells
- You are asked for a count of ways, a minimum cost or a maximum total
- The answer at i depends on only a few earlier positions
- A plain recursion keeps solving the same suffix again and again
Key idea
Define dp[i] from a handful of earlier answers (i-1, i-2) and fill left to right, collapsing an exponential recursion tree into one O(n) pass; rolling the last few values into variables cuts space to O(1).
Typical complexity
O(n) time, O(1) space
| # | Common problems | Level | Our solution | Practice |
|---|---|---|---|---|
| 1 | Climbing Stairs | Easy | Read solution | LeetCode ↗ |
| 2 | Min Cost Climbing Stairs | Easy | Read solution | LeetCode ↗ |
| 3 | House Robber | Medium | Read solution | LeetCode ↗ |
| 4 | Maximum Subarray | Medium | Read solution | LeetCode ↗ |
| 5 | House Robber II | Medium | Read solution | LeetCode ↗ |
| 6 | Best Time to Buy and Sell Stock with Cooldown | Medium | Read solution | LeetCode ↗ |
The instinct
When a problem walks along a single sequence (stairs, houses, days, characters) and asks for a count, a minimum or a maximum, try to answer "what is the best I can do ending at (or up to) position i?" If that answer can be built from the answers at i-1 and i-2 (or a few more), you have 1-D DP. Brute-force recursion explores the same suffixes over and over; storing each position's answer once turns an exponential tree into a straight line.
The gateway examples are Climbing Stairs (Fibonacci in disguise) and House Robber (take this house and jump two, or skip it).
Recognise it
| Signal in the problem | Why it points here |
|---|---|
| "how many distinct ways to reach step n" taking 1 or 2 steps | Ways(n) = ways from the last possible move sources; a Fibonacci-like sum. |
| "cannot pick two adjacent elements" | Take-or-skip choice: dp[i] = max(dp[i-1], dp[i-2] + val). |
| "minimum cost to reach the top", paying per step | Min over the positions you could have jumped from (Min Cost Climbing Stairs). |
| Houses arranged "in a circle" | Same recurrence run twice: drop the first item, then drop the last (House Robber II). |
| "maximum sum / product of a contiguous subarray" | dp ending at i: extend the previous run or restart here (Kadane). |
| Each day you are in one of a few modes (holding, cooldown, free) | 1-D DP with a small state per index, a tiny state machine. |
| Recursive solution with a single changing integer argument | Memoise on that integer, then convert to a loop. |
Not this pattern if...
- A greedy choice is provably optimal (e.g., Jump Game reachability): DP works but is overkill.
- The answer at i depends on all earlier j with a comparison (that is the LIS pattern) or on a capacity/target (that is knapsack).
- Two sequences or two indices are involved: you need a 2-D table (string DP, grid DP).
Memory hack
"Look back, pick best, roll forward." Every DP is four answers: state (what dp[i] means), choice (what you can do at i), base case (the first one or two values), and order (left to right so the past is ready).
Analogy: you are climbing stairs in the dark with a notebook. On each stair you write one number - the best result for reaching this stair - computed only from what you wrote on the last one or two stairs. You never need to flip back further, so a sticky note with two numbers is enough.
Say it out loud in the interview:
- "dp[i] means the best answer for the first i items / ending at i."
- "At i I can either take it or skip it (or step from i-1 / i-2), so dp[i] = combine(those)."
- "Base cases are dp[0] and dp[1]; I fill left to right, and since I only look back two, I can keep two variables."
How it works
Define the state precisely, write the recurrence, seed the base cases, and loop in an order where every dependency is already computed. For House Robber, dp[i] = most money from the first i houses. At house i you either skip it (keep dp[i-1]) or rob it (dp[i-2] + nums[i-1]).
Trace on nums = [2, 7, 9, 3, 1]:
| i | house value | skip = dp[i-1] | rob = dp[i-2] + value | dp[i] |
|---|---|---|---|---|
| 0 | - | - | - | 0 |
| 1 | 2 | 0 | 0 + 2 = 2 | 2 |
| 2 | 7 | 2 | 0 + 7 = 7 | 7 |
| 3 | 9 | 7 | 2 + 9 = 11 | 11 |
| 4 | 3 | 11 | 7 + 3 = 10 | 11 |
| 5 | 1 | 11 | 11 + 1 = 12 | 12 |
Only the two most recent dp values are ever read, so prev2, prev1 replace the array. A good workflow in interviews: recursion → memoisation → bottom-up table → rolling variables, saying out loud why each step is safe.
Java template
import java.util.*; class OneDimensionalDP { // Bottom-up with a full table: easiest to get right first. static int solveTable(int[] a) { int n = a.length; int[] dp = new int[n + 1]; dp[0] = 0; // base case: nothing chosen if (n >= 1) dp[1] = a[0]; // base case: first element for (int i = 2; i <= n; i++) { // choice: skip a[i-1] vs take a[i-1] and jump back two dp[i] = Math.max(dp[i - 1], dp[i - 2] + a[i - 1]); } return dp[n]; } // Same recurrence with O(1) space: roll the last two answers. static int solveRolling(int[] a, int from, int to) { // inclusive range, handy for circular variants int prev2 = 0, prev1 = 0; for (int i = from; i <= to; i++) { int cur = Math.max(prev1, prev2 + a[i]); // replace with problem-specific combine prev2 = prev1; prev1 = cur; } return prev1; } // Circular array: the first and last items cannot both be used. static int solveCircular(int[] a) { int n = a.length; if (n == 1) return a[0]; return Math.max(solveRolling(a, 0, n - 2), solveRolling(a, 1, n - 1)); } // Top-down memo: write this first if the recurrence is unclear. static int ways(int i, int[] memo) { if (i <= 1) return 1; // base: one way to stand at step 0 or 1 if (memo[i] != 0) return memo[i]; return memo[i] = ways(i - 1, memo) + ways(i - 2, memo); } }
Complexity
- Time: O(n × k), where k is how many earlier positions each step looks at - O(n) for the classic two-lookback problems.
- Space: O(n) for the table or memo; O(1) after rolling to k variables. The recursive memo also uses O(n) call stack, which can overflow for n around 10⁵ in Java, so prefer bottom-up there.
Variations
- Counting ways: Climbing Stairs -
dp[i] = dp[i-1] + dp[i-2]; with steps from a set S, sum over S. - Min cost with lookback: Min Cost Climbing Stairs -
dp[i] = cost[i] + min(dp[i-1], dp[i-2]); the answer is the cheaper of the last two. - Take or skip (no adjacent): House Robber; Delete and Earn reduces to it after bucketing values.
- Circular constraint: House Robber II - solve two linear ranges and take the max.
- Ending-here DP: Maximum Subarray and Maximum Product Subarray - track the best run ending at i (for products, track both max and min, since a negative flips them).
- State machine per index: Best Time to Buy and Sell Stock with Cooldown - a few variables (hold, sold, rest) updated together each day.
- Prefix decoding: Decode Ways - a single-string cousin where dp[i] reads one or two characters back; covered in String DP.
Common mistakes
Updating rolling variables in the wrong order overwrites a value you still need. Compute cur from the old pair first, then shift: prev2 = prev1; prev1 = cur;.
- Vague state. "dp[i] is the answer" is not enough - say whether it covers the first i items or ends exactly at i; the recurrence and final answer differ.
- Off-by-one base cases. Decide whether dp is indexed by items (size n + 1) or positions (size n) and stay consistent.
- Forgetting tiny inputs. n = 0, n = 1 and, for the circular version, n = 1 need explicit handling.
- Greedy temptation. Picking the larger of neighbouring houses locally fails on inputs like
[2, 1, 1, 2]. - Deep recursion in Java. Top-down memo on large n can throw
StackOverflowError; convert to a loop.
All practice problems
4 problems on this site use this pattern, easiest first. Solve them in order and say the instinct out loud before you code.