πΉ 1. Why Subsequence DP?
A subsequence is formed by deleting elements (or characters) without changing the relative order.
Example:"ace"
is a subsequence of"abcde"
, but"aec"
is not.-
Many DP problems boil down to:
- Should I include this element in my subsequence or skip it?
- Solve recursively β store results β optimize with DP.
These problems usually have a Pick / Not Pick choice.
πΉ 2. Core Template for Subsequence DP
For each element arr[i]
or character s[i]
:
- Pick it β contribute to subsequence.
- Skip it β move ahead.
DP stores the best/maximum/minimum/count result for each choice.
πΉ 3. Classic Subsequence DP Problems (with Code)
Letβs cover a wide variety of problems β from basic to advanced.
β Example 1: Longest Increasing Subsequence (LIS)
Problem: Find the length of the longest increasing subsequence in an array.
Idea:
- For each element, check all smaller elements before it.
- Extend LIS ending at that element.
Code (O(NΒ²)):
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
int maxLen = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
maxLen = Math.max(maxLen, dp[i]);
}
return maxLen;
}
πΉ Variation:
-
Max Sum Increasing Subsequence β instead of
+1
, addnums[i]
.
β Example 2: Longest Common Subsequence (LCS)
Problem: Find the longest subsequence common to two strings.
Idea:
- Compare last characters.
- If equal β add 1 + result for previous indices.
- Else β max of skipping one from either string.
Code:
public int lcs(String s1, String s2) {
int n = s1.length(), m = s2.length();
int[][] dp = new int[n+1][m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s1.charAt(i-1) == s2.charAt(j-1)) {
dp[i][j] = 1 + dp[i-1][j-1];
} else {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[n][m];
}
πΉ Variations:
-
Longest Palindromic Subsequence β LCS between
s
andreverse(s)
. -
Shortest Common Supersequence β
len(s1) + len(s2) - LCS(s1, s2)
.
β Example 3: Edit Distance (Levenshtein)
Problem: Minimum insert/delete/replace to convert word1
β word2
.
Idea:
- If last characters are equal β no operation needed.
- Else β consider insert, delete, replace.
- Take minimum.
Code:
public int minDistance(String word1, String word2) {
int n = word1.length(), m = word2.length();
int[][] dp = new int[n+1][m+1];
for (int i = 0; i <= n; i++) dp[i][0] = i; // delete
for (int j = 0; j <= m; j++) dp[0][j] = j; // insert
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = 1 + Math.min(dp[i-1][j], // delete
Math.min(dp[i][j-1], // insert
dp[i-1][j-1]));// replace
}
}
}
return dp[n][m];
}
β Example 4: Count Subsequences with Target Sum
Problem: Count subsets of an array with sum = target.
Idea:
-
For each element:
- Include β add to sum.
- Exclude β skip.
Code:
public int countSubsets(int[] nums, int target) {
int n = nums.length;
int[][] dp = new int[n+1][target+1];
dp[0][0] = 1; // base case
for (int i = 1; i <= n; i++) {
for (int sum = 0; sum <= target; sum++) {
dp[i][sum] = dp[i-1][sum]; // exclude
if (sum >= nums[i-1]) {
dp[i][sum] += dp[i-1][sum - nums[i-1]]; // include
}
}
}
return dp[n][target];
}
β Example 5: Distinct Subsequences (LeetCode 115)
Problem: Count how many subsequences of s
equal t
.
Idea:
-
If chars match β two options:
- Use the char.
- Skip the char.
Else β skip only.
Code:
public int numDistinct(String s, String t) {
int n = s.length(), m = t.length();
long[][] dp = new long[n+1][m+1];
for (int i = 0; i <= n; i++) dp[i][0] = 1; // empty t
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s.charAt(i-1) == t.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
} else {
dp[i][j] = dp[i-1][j];
}
}
}
return (int) dp[n][m];
}
β Example 6: Minimum Deletions to Make a Palindrome
Idea:
- Find Longest Palindromic Subsequence (LPS).
- Answer = length - LPS.
Code:
public int minDeletions(String s) {
String rev = new StringBuilder(s).reverse().toString();
int lps = lcs(s, rev); // reuse LCS
return s.length() - lps;
}
β Example 7: Maximum Sum Increasing Subsequence
Idea:
- Like LIS but track sums.
Code:
public int maxSumLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int maxSum = nums[0];
for (int i = 0; i < n; i++) {
dp[i] = nums[i];
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + nums[i]);
}
}
maxSum = Math.max(maxSum, dp[i]);
}
return maxSum;
}
πΉ 4. Optimization Techniques
- Space Optimization: Use 1D arrays when only last row/column is needed (e.g., LCS, Edit Distance).
- Binary Search: Optimize LIS to O(N log N).
- Bitmask DP: Useful when N β€ 20.
- String Reverse Trick: For palindrome problems.
πΉ 5. Real-World Uses
- Text diffing (git diff, plagiarism check) β LCS.
- Spell-check/autocorrect β Edit Distance.
- DNA sequence matching β LCS, Edit Distance.
- Recommendation systems β LIS-type ranking.
- Compression algorithms β repeated subsequences.
πΉ 6. Interview Tips
- Always clarify subsequence vs substring.
- For 2-string problems β think 2D DP.
- If asked for βmin operationsβ β try LCS or Edit Distance logic.
- If asked for βcount waysβ β usually DP counting paths.
- Keep reusable templates ready (like LCS).
Top comments (0)