Skip to content
advanced Phase 6 · Dynamic Programming

2D DP

Master 2D state space problems like grid paths and edit distance.

1h 30m
6 problems
Topic Progress 0%

Grid-Based DP Problems

Grid DP problems involve finding optimal paths or counts in a 2D grid.

Unique Paths

// Count paths from top-left to bottom-right (only right/down moves)
public int uniquePaths(int m, int n) {
    int[][] dp = new int[m][n];
    
    // Base cases: first row and first column have 1 path each
    for (int i = 0; i < m; i++) dp[i][0] = 1;
    for (int j = 0; j < n; j++) dp[0][j] = 1;
    
    // Fill the grid
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];  // From top + from left
        }
    }
    
    return dp[m - 1][n - 1];
}

// Space-optimized: O(n) space
public int uniquePathsOptimized(int m, int n) {
    int[] dp = new int[n];
    Arrays.fill(dp, 1);
    
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[j] += dp[j - 1];  // dp[j] (from top) + dp[j-1] (from left)
        }
    }
    
    return dp[n - 1];
}

Minimum Path Sum

// Find path with minimum sum from top-left to bottom-right
public int minPathSum(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (i == 0 && j == 0) continue;  // Start cell
            else if (i == 0) grid[i][j] += grid[i][j - 1];  // First row
            else if (j == 0) grid[i][j] += grid[i - 1][j];  // First column
            else grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]);
        }
    }
    
    return grid[m - 1][n - 1];
}

Unique Paths with Obstacles

// Grid with obstacles (1 = obstacle, 0 = empty)
public int uniquePathsWithObstacles(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    
    if (grid[0][0] == 1 || grid[m-1][n-1] == 1) return 0;
    
    int[][] dp = new int[m][n];
    dp[0][0] = 1;
    
    for (int i = 1; i < m; i++) {
        dp[i][0] = (grid[i][0] == 0 && dp[i-1][0] == 1) ? 1 : 0;
    }
    for (int j = 1; j < n; j++) {
        dp[0][j] = (grid[0][j] == 0 && dp[0][j-1] == 1) ? 1 : 0;
    }
    
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            if (grid[i][j] == 0) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
    }
    
    return dp[m-1][n-1];
}

Key Pattern for Grid DP

// State: dp[i][j] = optimal value at cell (i,j)
// Transition: dp[i][j] = f(dp[i-1][j], dp[i][j-1])  // for 4-directional
// Or: dp[i][j] = f(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])  // for diagonal

Space Optimization for Grid DP

// If transition only depends on previous row, use single row
int[] dp = new int[n];
for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        if (i == 0 && j == 0) dp[j] = grid[0][0];
        else if (i == 0) dp[j] = dp[j-1] + grid[0][j];
        else if (j == 0) dp[j] = dp[j] + grid[i][0];
        else dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j];
    }
}
return dp[n-1];

String DP Problems

String DP problems involve comparing or transforming two strings.

Longest Common Subsequence (LCS)

// Find length of longest common subsequence of two strings
public int longestCommonSubsequence(String text1, String text2) {
    int m = text1.length(), n = text2.length();
    int[][] dp = new int[m + 1][n + 1];
    
    // dp[i][j] = LCS length of text1[0..i-1] and text2[0..j-1]
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1] + 1;  // Characters match
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);  // Skip one
            }
        }
    }
    
    return dp[m][n];
}

// Space-optimized: O(n) space
public int lcsOptimized(String text1, String text2) {
    int m = text1.length(), n = text2.length();
    int[] dp = new int[n + 1];
    
    for (int i = 1; i <= m; i++) {
        int prev = 0;  // dp[i-1][j-1]
        for (int j = 1; j <= n; j++) {
            int temp = dp[j];
            if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
                dp[j] = prev + 1;
            } else {
                dp[j] = Math.max(dp[j], dp[j - 1]);
            }
            prev = temp;
        }
    }
    
    return dp[n];
}

Edit Distance

// Minimum operations to convert word1 to word2
// Operations: insert, delete, replace
public int editDistance(String word1, String word2) {
    int m = word1.length(), n = word2.length();
    int[][] dp = new int[m + 1][n + 1];
    
    // Base cases: converting empty string
    for (int i = 0; i <= m; i++) dp[i][0] = i;  // Delete all
    for (int j = 0; j <= n; j++) dp[0][j] = j;  // Insert all
    
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];  // No operation needed
            } else {
                dp[i][j] = 1 + Math.min(
                    dp[i - 1][j - 1],  // Replace
                    Math.min(dp[i - 1][j],   // Delete
                             dp[i][j - 1])    // Insert
                );
            }
        }
    }
    
    return dp[m][n];
}

Longest Palindromic Subsequence

// Find longest palindromic subsequence in a string
public int longestPalindromeSubseq(String s) {
    int n = s.length();
    int[][] dp = new int[n][n];
    
    // Base case: single character
    for (int i = 0; i < n; i++) dp[i][i] = 1;
    
    // Fill for lengths 2 to n
    for (int len = 2; len <= n; len++) {
        for (int i = 0; i <= n - len; i++) {
            int j = i + len - 1;
            if (s.charAt(i) == s.charAt(j)) {
                dp[i][j] = dp[i + 1][j - 1] + 2;
            } else {
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
    }
    
    return dp[0][n - 1];
}

String DP Patterns

Problem State Transition
LCS dp[i][j] = LCS of s1[0..i-1], s2[0..j-1] match: dp[i-1][j-1]+1, else: max(dp[i-1][j], dp[i][j-1])
Edit Distance dp[i][j] = ops to convert s1[0..i-1] to s2[0..j-1] match: dp[i-1][j-1], else: 1+min(replace, delete, insert)
Palindrome dp[i][j] = LPS in s[i..j] match: dp[i+1][j-1]+2, else: max(dp[i+1][j], dp[i][j-1])

Practice Problems

0 / 1 solved
Longest Common Subsequence
2D String DP

Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0. A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.

Example:

Input: text1 = "abcde", text2 = "ace"

Output: 3

The longest common subsequence is "ace" and its length is 3.

Edge Cases:

  • One or both strings empty — answer is 0
  • Both strings identical — answer is the string length
  • No common characters — answer is 0
  • One string is subsequence of the other — answer is the shorter string length
  • Strings with all same characters

Quiz

1. In Edit Distance, what are the three operations allowed?

Question 1 options

2. What is the state transition for LCS when characters match?

Question 2 options

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

Question 3 options

Flashcards

Question

What is the state transition for Edit Distance?

Answer

If chars match: dp[i][j] = dp[i-1][j-1]. Else: dp[i][j] = 1 + min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) representing replace, delete, insert.

Question

How do you optimize 2D DP space from O(m*n) to O(n)?

Answer

When dp[i][j] only depends on current and previous row, use a single 1D array and update carefully left-to-right or right-to-left.

Question

2D Dynamic Programming best practices

Answer

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

Revision Notes

Key Takeaways

  • 1. Grid DP: dp[i][j] depends on neighbors (top, left, diagonal)
  • 2. String DP: dp[i][j] depends on comparing characters at positions i-1, j-1
  • 3. Space optimization uses single row when only previous row needed
  • 4. Always handle base cases for first row and first column

Interview Tips

  • Draw out small examples to understand state transitions
  • Clarify if subsequence (non-contiguous) or substring (contiguous)
  • Discuss space optimization after giving O(mn) solution
  • For Edit Distance, explain the three operations clearly

Cheat Sheet

2D DP Cheat Sheet

Grid DP Patterns:

  • Unique paths: dp[i][j] = dp[i-1][j] + dp[i][j-1]
  • Min path sum: dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
  • Obstacles: set dp[i][j] = 0 when obstacle

String DP Patterns:

  • LCS: match: dp[i-1][j-1]+1, else: max(dp[i-1][j], dp[i][j-1])
  • Edit Distance: match: dp[i-1][j-1], else: 1+min(replace, delete, insert)
  • Palindrome: match: dp[i+1][j-1]+2, else: max(dp[i+1][j], dp[i][j-1])

Space Optimization:

  • Use single row when transition depends on previous row only
  • Update direction matters (left-to-right vs right-to-left)

Base Cases:

  • First row/column usually initialized to 1 or 0
  • Empty string comparisons: dp[0][j] = j, dp[i][0] = i