Pattern #67
1D Dynamic Programming
Master single-dimensional DP arrays and rolling variable space optimization. Express subproblems with one variable, identify transition windows, and optimize memory to O(1).
Must Solve
20 core questions — solve these first.
- 1.Climbing Stairsdp[i] = dp[i-1] + dp[i-2] with O(1) space optimizationeasy
- 2.Min Cost Climbing Stairsdp[i] = cost[i] + min(dp[i-1], dp[i-2])easy
- 3.House RobberTake vs Skip: dp[i] = max(dp[i-1], nums[i] + dp[i-2])medium
- 4.House Robber IICircular array: run House Robber on 0..N-2 and 1..N-1medium
- 5.Fibonacci NumberBase 1D DP: prev2, prev1, curr variableseasy
- 6.Decode Ways1D DP: dp[i] += dp[i-1] (if 1-digit valid) + dp[i-2] (if 2-digit valid)medium
- 7.Coin ChangeAmount 1D DP: dp[a] = min(dp[a], 1 + dp[a-coin]) initialized to INFmedium
- 8.Coin Change IICombination count: dp[a] += dp[a-coin] with outer coin loopmedium
- 9.Perfect SquaresAmount 1D DP: dp[i] = min(dp[i], 1 + dp[i - s*s])medium
- 10.Word BreakString suffix 1D DP: dp[i] = true if dp[j] && wordDict.contains(s[j:i])medium
- 11.Maximum SubarrayKadane 1D DP: dp[i] = max(nums[i], nums[i] + dp[i-1])easy
- 12.Maximum Product SubarrayTrack currentMax and currentMin 1D DP variablesmedium
- 13.Longest Increasing Subsequence1D DP ending at i: dp[i] = 1 + max(dp[j]) for j < imedium
- 14.Partition Equal Subset SumTarget sum 1D DP: right-to-left loop for target = sum/2medium
- 15.Target SumSubset sum 1D DP: convert target to positive sum P = (sum + target)/2medium
- 16.0/1 Knapsack — Space OptimizedCapacity 1D DP: right-to-left loop ensures single item usemedium
- 17.Combination Sum IVPermutation 1D DP: outer target loop, inner coin loopmedium
- 18.Delete and EarnFrequency sum transformation into House Robber 1D DPmedium
- 19.Integer Break1D DP: dp[i] = max(j * (i-j), j * dp[i-j])medium
- 20.Best Time to Buy and Sell Stock variants1D State variables: hold, sold, reset updated dailymedium
Also Important
10 essential 1D DP variations worth practicing.
- 21.Jump Game variantsBoolean or min steps 1D DP array reachable from leftmedium
- 22.Tribonacci Number3-state 1D DP: dp[i] = dp[i-1] + dp[i-2] + dp[i-3]easy
- 23.Domino and Tromino TilingMulti-state 1D DP for board coverage possibilitiesmedium
- 24.House Robber style schedulingNon-adjacent interval selection 1D DPmedium
- 25.Minimum Cost for TicketsDay-based 1D DP: min cost for 1-day, 7-day, 30-day passesmedium
- 26.Number of Dice Rolls With Target SumTarget 1D DP: sum combination count across dicemedium
- 27.Ugly Number II3-pointer 1D DP: min(dp[i2]*2, dp[i3]*3, dp[i5]*5)medium
- 28.Longest Valid Parentheses — DP approach1D DP ending at i: dp[i] tracks longest valid match ending at ihard
- 29.Maximum Sum Circular Subarray — relatedKadane 1D DP min/max total sum subtractionmedium
- 30.Weighted Interval Scheduling — DP + Binary Search1D DP on sorted end times with binary search for non-overlapping predecessorhard
How to Think
Define what one DP cell dp[i] represents, then build transitions from earlier positions or amounts.
- Answer mainly depends on position i?dp[i]
- Current answer depends on earlier positions?1D DP
- Only previous 1–2 states needed?Space Optimization O(1)
- State dimension is numerical (amount / sum)?1D Amount DP
- Need max subarray sum ending at i?Kadane 1D DP
Go Quick Reference — 1D DP
Compilable Go implementations showing Space-Optimized House Robber O(1) and 1D Coin Change Minimum Amount array.
package main
import "fmt"
// Space-Optimized 1D DP for House Robber: O(N) time, O(1) space
func rob(nums []int) int {
if len(nums) == 0 {
return 0
}
prev2, prev1 := 0, 0
for _, num := range nums {
// Transition: current = max(skip, take)
take := num + prev2
skip := prev1
current := take
if skip > take {
current = skip
}
prev2 = prev1
prev1 = current
}
return prev1
}
// 1D Amount DP for Coin Change: O(Amount * Coins) time, O(Amount) space
func coinChange(coins []int, amount int) int {
dp := make([]int, amount+1)
const inf = 1e9
for i := 1; i <= amount; i++ {
dp[i] = inf
}
dp[0] = 0 // Base case
for a := 1; a <= amount; a++ {
for _, coin := range coins {
if a >= coin && dp[a-coin]+1 < dp[a] {
dp[a] = dp[a-coin] + 1
}
}
}
if dp[amount] == inf {
return -1
}
return dp[amount]
}
func main() {
fmt.Println("Max Robbed:", rob([]int{2, 7, 9, 3, 1})) // 12
fmt.Println("Min Coins:", coinChange([]int{1, 2, 5}, 11)) // 3
}👉 1D DP: O(N) or O(Amount) time and O(1) or O(N) space.
Core 1D DP Patterns & Shapes
Common 1D Transition Shapes
• 1 State Back: dp[i] ← dp[i-1] (Kadane, Stock buy/sell).
• 2 States Back: dp[i] ← dp[i-1], dp[i-2] (Climbing Stairs, House Robber).
• All Previous j < i: dp[i] ← max(dp[j]) (LIS - O(N²) time).
• Amount / Capacity Shift: dp[a] ← dp[a - coin] (Coin Change, Knapsack).
"Ending At" vs "Overall Best"
• In LIS and Kadane, dp[i] means "best answer ending EXACTLY at index i".
• The final answer is max(dp) across the array, NOT necessarily dp[N-1]!
• Always distinguish between target cell vs overall array maximum.
Define dp[i] Cell Meaning → Set Base Cases → Transition → Answer
Previous 1–2 States → Rolling variables optimize space to O(1)
0/1 Knapsack 1D Table → Capacity loop runs Right-to-Left
Unbounded Knapsack 1D Table → Capacity loop runs Left-to-Right
LIS / Subarray DP → Answer is max(dp), not always dp[last]1D DP Variants & Space Optimization
0/1 vs Unbounded 1D Update Direction
• 0/1 Knapsack / Subset Sum: Update capacity Right to Left (w = W down to weight) to prevent item reuse.
• Unbounded Knapsack / Coin Change: Update capacity Left to Right (w = weight up to W) to allow item reuse.
Rolling Variables Technique
When dp[i] depends only on a fixed sliding window of size K (e.g. 2 states back):
Replace the full dp[N] array with K variables (prev2, prev1, current).
Reduces extra space from O(N) to O(1).
1D State Does Not Always Mean Array Index
The single state dimension in 1D DP can represent:
• Array Index: dp[i] (House Robber, LIS).
• Numerical Amount / Capacity: dp[amount] or dp[weight] (Coin Change, Knapsack).
• Sum / Count: dp[target] (Target Sum).
As long as one variable uniquely identifies the subproblem, it is a 1D DP pattern.
Common Interview Mistakes
- • Coding before explicitly defining what dp[i] represents in plain language.
- • Wrong base case initializations (e.g. using 0 for minimum problems instead of INF).
- • Returning dp[N-1] when the answer is max(dp) across the array (common mistake in LIS and Kadane).
- • Running 0/1 Knapsack 1D capacity loop left-to-right (accidentally allowing item reuse).
- • Assuming all 1D DP solutions run in O(N) time (LIS is O(N²) because each state scans all j < i).
- • Optimizing space to O(1) prematurely before validating the full array transition logic.
- • Confusing array index state (dp[i]) with numerical amount state (dp[amount]).
- • Failing to handle negative numbers in Maximum Product Subarray (requires currentMax and currentMin).
Interview Rules
Single parameter defines subproblem → 1D DP
Rule 1 → Define dp[i] meaning explicitly
Rule 2 → Set base cases
Rule 3 → Identify previous state window (1 state, 2 states, or all j < i)
Rule 4 → 0/1 Knapsack 1D = Capacity loop Right-to-Left
Rule 5 → Unbounded Knapsack 1D = Capacity loop Left-to-Right
Rule 6 → Window of size 1–2? → Rolling variables for O(1) space
Time Complexity → States × Work per State
Space Complexity → O(N) Array or O(1) Rolling Variables💡 Golden Rule: If one variable completely describes the subproblem, store the answer in one DP dimension and build each state from already-solved states.
Production Thinking
Budget & Financial Optimization → 1D amount DP allocates cloud resources or spending budgets under fixed limits.
Time Window Scheduling → dp[t] tracks optimal system throughput or job completions by time t.
Resource Capacity Management → 1D capacity tables model memory, storage, or weight thresholds with O(1) memory overhead.
Production warning → space optimization reduces array size, but premature variable overwrites produce subtle bug corruptions.
Remember This
1D DP State: dp[i] or dp[amount]
Golden Steps: Define Cell → Base Cases → Transition → Fill → Answer
0/1 Knapsack 1D: Loop capacity Right-to-Left
Unbounded 1D: Loop capacity Left-to-Right
LIS & Kadane: dp[i] means "ending at i"; final answer is max(dp)
Rolling variables (prev2, prev1) achieve O(1) memory