The Longest Common Subsequence (LCS) problem is a classic problem in computer science. Given two strings ‘s1‘ and ‘s2‘, the task is to find the longest common subsequence of the two strings.
A subsequence is a sequence that can be derived from another sequence by deleting some or no elements without changing the order of the remaining elements.
For example, if ‘s1‘ = "ABCD" and ‘s2‘ = "ACDB", then the LCS of ‘s1‘ and ‘s2‘ is "ACD".
One approach to solving this problem is by using dynamic programming. The basic idea is to construct a 2D array
‘dp[len1+1][len2+1]‘, where ‘len1‘ and ‘len2‘ are the lengths of ‘s1‘ and ‘s2‘, respectively. The value of ‘dp[i][j]‘ represents the length of the LCS of the first ‘i‘ characters of ‘s1‘ and the first ‘j‘ characters of ‘s2‘.
We can fill up the ‘dp‘ array iteratively, starting from the base cases where one of the strings is empty (i.e., ‘dp[i][0]‘ or ‘dp[0][j]‘ equals 0), and then filling up the rest of the array.
The key observation is that if the last characters of ‘s1‘ and ‘s2‘ match, then the LCS of the two strings must include that character. Otherwise, the LCS can either include the last character of ‘s1‘ or the last character of ‘s2‘, but not both.
Therefore, the recurrence relation for computing ‘dp[i][j]‘ is:
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
The final answer will be stored in ‘dp[len1][len2]‘.
Here’s an example implementation of the LCS algorithm in Java:
public static String LCS(String s1, String s2) {
int len1 = s1.length(), len2 = s2.length();
int[][] dp = new int[len1 + 1][len2 + 1];
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
StringBuilder sb = new StringBuilder();
int i = len1, j = len2;
while (i > 0 && j > 0) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
sb.append(s1.charAt(i - 1));
i--;
j--;
} else if (dp[i - 1][j] > dp[i][j - 1]) {
i--;
} else {
j--;
}
}
return sb.reverse().toString();
}
In this implementation, we first compute the ‘dp‘ array as described above, and then use it to construct the LCS string by following the backtrack process. The backtrack process starts from the bottom-right corner of the ‘dp‘ array and moves upwards and/or leftwards depending on the values of ‘dp[i-1][j]‘ and ‘dp[i][j-1]‘. Finally, we reverse the string and return it as the output.