Skip to content
advanced Phase 6 · Dynamic Programming

1D DP

Solve classic 1D DP problems like climbing stairs and house robber.

1h 15m
6 problems
Topic Progress 0%

1D DP Patterns and Templates

1D DP problems use a single array where dp[i] represents the optimal solution for the subproblem ending at index i.

Pattern 1: Fibonacci-like

Problems where each state depends on the previous one or two states.

// Template: dp[i] = dp[i-1] + dp[i-2]
// Example: Climbing Stairs, Fibonacci
public int solveFibonacci(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 0;
    dp[1] = 1;
    
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    
    return dp[n];
}

Pattern 2: Maximum/Minimum Sum

Select elements to maximize/minimize sum with constraints.

// House Robber: Maximum sum of non-adjacent elements
// dp[i] = max value considering houses 0..i
public int rob(int[] nums) {
    int n = nums.length;
    if (n == 0) return 0;
    if (n == 1) return nums[0];
    
    int[] dp = new int[n];
    dp[0] = nums[0];
    dp[1] = Math.max(nums[0], nums[1]);
    
    for (int i = 2; i < n; i++) {
        dp[i] = Math.max(dp[i - 1],      // Skip current house
                         dp[i - 2] + nums[i]);  // Rob current house
    }
    
    return dp[n - 1];
}

// Space-optimized version
public int robOptimized(int[] nums) {
    int n = nums.length;
    if (n == 0) return 0;
    if (n == 1) return nums[0];
    
    int prev2 = nums[0];
    int prev1 = Math.max(nums[0], nums[1]);
    
    for (int i = 2; i < n; i++) {
        int curr = Math.max(prev1, prev2 + nums[i]);
        prev2 = prev1;
        prev1 = curr;
    }
    
    return prev1;
}

Pattern 3: Kadane's Algorithm (Maximum Subarray)

// Maximum contiguous subarray sum
// dp[i] = max subarray sum ending at index i
public int maxSubArray(int[] nums) {
    int maxSoFar = nums[0];
    int maxEndingHere = nums[0];
    
    for (int i = 1; i < nums.length; i++) {
        // Either extend previous subarray or start new one
        maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }
    
    return maxSoFar;
}

Pattern 4: Decode Ways

// Count number of ways to decode a string of digits
// '1' -> 'A', '2' -> 'B', ..., '26' -> 'Z'
public int numDecodings(String s) {
    int n = s.length();
    int[] dp = new int[n + 1];
    dp[0] = 1;  // Empty string has 1 way
    dp[1] = s.charAt(0) != '0' ? 1 : 0;
    
    for (int i = 2; i <= n; i++) {
        // Single digit decode
        if (s.charAt(i - 1) != '0') {
            dp[i] += dp[i - 1];
        }
        
        // Two digit decode
        int twoDigit = Integer.parseInt(s.substring(i - 2, i));
        if (twoDigit >= 10 && twoDigit <= 26) {
            dp[i] += dp[i - 2];
        }
    }
    
    return dp[n];
}

When to Use 1D DP

  • Problem has sequential structure (array/string)
  • State depends on a constant number of previous states
  • You need to find optimal value (max/min/count)
  • Greedy doesn't work (counterexample exists)

Space Optimization Techniques

Why Optimize Space?

In many 1D DP problems, dp[i] only depends on a few previous values. We can reduce space from O(n) to O(1).

Observation

// If dp[i] = f(dp[i-1], dp[i-2], ..., dp[i-k])
// We only need to keep track of the last k values

Example: House Robber with O(1) Space

public int rob(int[] nums) {
    int n = nums.length;
    if (n == 0) return 0;
    if (n == 1) return nums[0];
    
    // Only need prev2 and prev1
    int prev2 = nums[0];
    int prev1 = Math.max(nums[0], nums[1]);
    
    for (int i = 2; i < n; i++) {
        int curr = Math.max(prev1, prev2 + nums[i]);
        prev2 = prev1;
        prev1 = curr;
    }
    
    return prev1;
}

Generic Pattern for Rolling Variables

// Instead of:
int[] dp = new int[n + 1];
for (int i = 0; i <= n; i++) {
    dp[i] = /* ... */;
}

// Use rolling variables:
int prev2 = baseValue1;
int prev1 = baseValue2;
for (int i = k; i <= n; i++) {
    int curr = /* depends on prev1, prev2, ... */;
    prev2 = prev1;
    prev1 = curr;
}
return prev1;  // or prev2 depending on the problem

Maximum Subarray with O(1) Space

public int maxSubArray(int[] nums) {
    int maxSoFar = nums[0];
    int maxEndingHere = nums[0];
    
    for (int i = 1; i < nums.length; i++) {
        maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }
    
    return maxSoFar;
}

Common Mistakes in Space Optimization

  1. Forgetting base cases: Ensure initial values are correct
  2. Overwriting values: Update in correct order
  3. Wrong return value: Return the right variable (prev1 vs prev2)
  4. Not handling n < k: When n is smaller than the number of variables needed

Practice Problems

0 / 5 solved
House Robber
Linear DP - Maximum Sum

You are a robber planning to rob houses along a street. Each house has a certain amount of money. The only constraint stopping you from robbing each of them is that adjacent houses have security systems connected. If two adjacent houses were broken into on the same night, the security system alerts the police. Given an integer array nums representing the amount of money of each house, return the maximum amount you can rob without alerting the police.

Example:

Input: nums = [1,2,3,1]

Output: 4

Rob house 1 (money = 1) and house 3 (money = 3). Total = 1 + 3 = 4.

Edge Cases:

  • Single house (rob it, return its value)
  • Two houses (rob the one with more money)
  • All houses have the same value
  • Strictly increasing values (rob every other house)
Coin Change
1D DP - Knapsack Variant

You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money. Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example:

Input: coins = [1,5,10,25], amount = 30

Output: 2

25 + 5 = 30, so 2 coins.

Edge Cases:

  • amount = 0 (zero coins needed, return 0)
  • No coin combination can form the amount (return -1)
  • Single coin denomination that doesn't divide the amount evenly
  • Coins array contains values larger than the amount (unusable for small subproblems)
Decode Ways
1D DP - Counting

A message consisting of letters is encoded as: 'A' -> 1, 'B' -> 2, ..., 'Z' -> 26. Given a string s of digits, return the number of ways to decode it.

Example:

Input: s = "226"

Output: 3

"226" can be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

Edge Cases:

  • Leading zero ('0' at start) — 0 ways to decode
  • '10' — only 1 way (10 = J)
  • '27' — only 1 way (2 and 7 separately, 27 is invalid)
  • '111' — 3 ways: 1-1-1, 11-1, 1-11
  • Single digit '0' — 0 ways
House Robber II
1D DP - Circular

All houses are arranged in a circle. If you rob the first house, you cannot rob the last. Return the maximum amount you can rob.

Example:

Input: nums = [2,3,2]

Output: 3

Rob house 2 (money = 3). Cannot rob house 1 and 3 together because they are adjacent in circle.

Edge Cases:

  • Single house — rob it
  • Two houses — rob the larger one
  • All zeros — answer is 0
  • All same value — rob ceil(n/2) houses
  • Strictly increasing values
Best Time to Buy and Sell Stock
Kadane's Algorithm

You are given an array `prices` where `prices[i]` is the price of a given stock on the `ith` day. You want to maximize your profit by choosing a **single day** to buy one stock and choosing a **different day in the future** to sell that stock. Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return `0`.

Example:

Input: prices = [7, 1, 5, 3, 6, 4]

Output: 5

Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6 - 1 = 5.

Edge Cases:

  • Single element array (no transaction possible, return 0)
  • Strictly decreasing prices (no profit possible)
  • All identical prices (profit is always 0)
  • Prices that increase then decrease (peak is not always the best sell point)

Quiz

1. In House Robber, what does dp[i] represent?

Question 1 options

2. What is the state transition for House Robber?

Question 2 options

3. What is a common mistake when implementing 1D Dynamic Programming?

Question 3 options

Flashcards

Question

What is Kadane's Algorithm used for?

Answer

Finding the maximum sum contiguous subarray in O(n) time. dp[i] = max(nums[i], dp[i-1] + nums[i]).

Question

When can you optimize 1D DP space from O(n) to O(1)?

Answer

When dp[i] depends only on a constant number of previous states (e.g., dp[i-1] and dp[i-2]). Use rolling variables instead of array.

Question

1D Dynamic Programming best practices

Answer

Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.

Revision Notes

Key Takeaways

  • 1. 1D DP is for sequential problems with constant-width dependency
  • 2. Always define dp[i] clearly before coding
  • 3. Space optimization is possible when recurrence has limited dependency
  • 4. Kadane's algorithm is the classic O(n) maximum subarray solution

Interview Tips

  • Start with O(n) space solution, then optimize
  • Draw out dp table for small inputs to verify
  • Explain the state transition clearly
  • Handle edge cases: empty array, single element

Cheat Sheet

1D DP Cheat Sheet

Common Patterns:

  • Fibonacci-like: dp[i] = dp[i-1] + dp[i-2]
  • Max sum non-adjacent: dp[i] = max(dp[i-1], dp[i-2] + nums[i])
  • Kadane's: maxEndingHere = max(nums[i], maxEndingHere + nums[i])

Space Optimization:

  • If dp[i] depends on dp[i-1] and dp[i-2], use two variables
  • If dp[i] depends on dp[i-1..i-k], use k variables

Template:

int prev2 = base1;
int prev1 = base2;
for (int i = k; i < n; i++) {
    int curr = f(prev1, prev2, ...);
    prev2 = prev1;
    prev1 = curr;
}
return prev1;

Key Insight:

  • Always ask: "What decision do I make at each step?"