Longest Common Subsequence
Let's solve the Longest Common Subsequence problem using Dynamic Programming.
Statement
Suppose you are given two strings. You need to find the length of the longest common subsequence between these two strings.
A subsequence is a string formed by removing some characters from the original string, while maintaining the relative position of the remaining characters. For example, “abd” is a subsequence of “abcd”, where the removed character is “c”.
If there is no common subsequence, then return 0.
Let’s say you have the following two strings:
- “cloud”
- “found”
The longest common subsequence between these two strings is “oud”, which has a length of .
Constraints:
-
str1.length
-
str2.length
str1
andstr2
contain only lowercase English characters.
Examples
No. | str1 | str2 | length |
1 | "bald" | "bad" | 3 |
2 | "nocturnal" | "nick" | 2 |
3 | "card" | "tissue" | 0 |
Try it yourself
Implement your solution in the following coding playground.
import java.util.*;public class Main{public static int longestCommonSubsequence(String str1, String str2) {// Write your code here// your code will replace the placeholder return statement belowreturn -1;}}
Note: If you clicked the “Submit” button and the code timed out, this means that your solution needs to be optimized in terms of running time.
Hint: Use dynamic programming and see the magic.
Solution
We will first explore the naive recursive solution to this problem and then see how it can be improved using the Longest Common Substring dynamic programming pattern.
Naive approach
A naive approach is to compare the characters of both strings based on the following rules:
-
If the current characters of both strings match, we move one position ahead in both strings.
-
If the current characters of both strings do not match, we recursively calculate the maximum length of moving one character forward in any one of the two strings i.e., we check if moving a character forward in either the first string or the second will give us a longer subsequence.
-
If we reach the end of either of the two strings, we return .
Let’s look at the following illustration to get a better understanding of the solution:
Let’s implement the algorithm as discussed above:
class LongestCommonSubsequence{// Helper function with updated signature: i is current index in str1, j is current index in str2public static int longestCommonSubsequenceHelper(String str1, String str2, int i, int j){// base caseif (i == str1.length() || j == str2.length())return 0;// if current characters match, increment 1else if (str1.charAt(i) == str2.charAt(j))return 1 + longestCommonSubsequenceHelper(str1, str2, i+1, j+1);// else take max of either of two possibilitiesreturn Math.max(longestCommonSubsequenceHelper(str1, str2, i+1, j),longestCommonSubsequenceHelper(str1, str2, i, j+1));}public static int longestCommonSubsequence(String str1, String str2){return longestCommonSubsequenceHelper(str1, str2, 0, 0);}// Driver Codepublic static void main(String[] args){String[] firstStrings = {"qstw", "setter", "abcde", "partner", "freedom"};String[] secondStrings = {"gofvn", "bat", "apple", "park", "redeem"};// You can uncomment the lines below and check how this recursive solution causes a time-out// String temp[] = Arrays.copyOf(firstStrings, firstStrings.length + 1);// temp[firstStrings.length] = "sjcneiurutvmpdkapbrcapjru";// firstStrings = temp;// String temp2[] = Arrays.copyOf(secondStrings, secondStrings.length + 1);// temp2[secondStrings.length] = "oidhfwepkxwebyurtunvidqlscmjbg";// secondStrings = temp2;for (int i = 0; i < firstStrings.length; i++){System.out.println(i + 1 + ".\tstr1: " + firstStrings[i] + "\n\tstr2: " + secondStrings[i]+ "\n\n\tThe length of the longest common subsequence is: " + longestCommonSubsequence(firstStrings[i], secondStrings[i]));System.out.println(PrintHyphens.repeat("-", 100));}}}
Note: Please observe that if you include the test case commented out in the driver code, the solution is likely to time out. Try to solve the larger problem using the dynamic programming solutions provided below and see the difference.
Time complexity
The time complexity of the naive approach is ...