The Longest Common Subsequence (LCS) problem is a classic computer science problem often solved using dynamic programming. Given two sequences, this problem involves finding the longest subsequence present in both of them. 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.
Hereβs how you can find the longest common subsequence of two strings using dynamic programming:
Letβs denote the two input strings as βX[0..m-1]β and βY[0..n-1]β. For this process, we can start by initially defining a 2D matrix βdp[][]β of size β(m+1)x(n+1)β.
Here, βdp[i][j]β will hold the length of the longest common subsequence of the prefixes βX[0..i-1]β and βY[0..j-1]β.
To clarify, here is the formula that will be used:
$$dp[i][j] =
\begin{cases}
0 & \text{if } i=0 \text{ or } j=0 \\
dp[i-1][j-1] + 1 & \text{if } X[i-1] = Y[j-1] \\
\max(dp[i-1][j], dp[i][j-1]) & \text{if } X[i-1] \neq Y[j-1]
\end{cases}$$
The approach behind this algorithm is as follows:
1. If βX[i-1]β is equal to βY[j-1]β, this means we have found a matching character in both strings. Thus, the LCS up to βi,jβ is the LCS up to βi-1,j-1β extended by this matching character, hence we add 1 to βdp[i-1][j-1]β.
2. If βX[i-1]β is not equal to βY[j-1]β, we have a choice to ignore either βX[i-1]β or βY[j-1]β. Select the previous cell that has the maximum LCS, i.e., maximum of βdp[i][j-1]β or βdp[i-1][j]β.
The LCS of the complete strings βXβ and βYβ is given by βdp[m][n]β which is the last cell.
For example, let βX = "ABCBDAB"` and βY = "BDCAB"`. The LCS is β"BCAB"`. Following the above approach, here is what the filled table would look like:
"" B D C A B
"" 0 0 0 0 0 0
A 0 0 0 0 1 1
B 0 1 1 1 1 2
C 0 1 1 2 2 2
B 0 1 1 2 2 3
D 0 1 2 2 2 3
A 0 1 2 2 3 3
B 0 1 2 2 3 4
Every cell βdp[i][j]β holds the LCS length of the prefixes βX[0...i-1]β and βY[0...j-1]β, thus the LCS length for whole βXβ and βYβ is βdp[m][n] = 4β, which matches with our LCS string β"BCAB"` length. So, the bottom-right cell has the length of the LCS.
Bear in mind, this algorithm does not return the actual LCS, but only its length. To find the actual LCS string, one has to backtrack from the βdp[m][n]β cell according to the following rules: - If βX[i-1] = Y[j-1]β, it means that this character is part of the LCS string, so add βX[i-1]β (or βY[j-1]β) to the LCS string and go diagonally up to βdp[i-1][j-1]β. - If βX[i-1] != Y[j-1]β, then go to the cell that contains the maximum value, which can be either βdp[i-1][j]β or βdp[i][j-1]β. If both have the same value, either choice can work.
This backtrack approach will complete the LCS algorithm for finding not just the length, but also the LCS string.
Time complexity of this solution is βO(m*n)β (where m and n are string lengths) for the LCS length computing and βO(m+n)β for the LCS string recovering, so overall linear in terms of strings length.