Redaksiya
The subsequence of a given sequence is a set of elements arranged in the same order as in the original sequence but not necessarily contiguous. A subsequence can be obtained from the original sequence by removing some of its elements.
For example, consider the sequence . Then
are subsequences;
are not subsequences;
The common subsequence of two sequences is a subsequence that appears in both sequences.
The longest common subsequence (LCS) is a common subsequence of maximum length.
For example, the longest common subsequence of the sequences and can be or . In this case, the length of the LCS is .
Let be the length of the longest common subsequence of the sequences and .
If , the LCS should be found among two options:
the prefixes and (their LCS is ),
the prefixes and (their LCS is ).
Return the maximum of these values:
If , add the current element to the LCS and consider the shorter prefixes and :
If one of the sequences is empty, then their LCS is also empty:
The recurrence relation for computing the LCS length is as follows:
Let’s consider an example of the calculations:
The values of will be stored in an array , where . Each subsequent row of the array is computed based on the previous one. Thus, to find the result, it is sufficient to store only two rows of length in memory.
Example
Let . The longest common subsequence is , and its length is .
, because .
, because .
Exercise
Fill the following table:
Algorithm implementation
The arrays and contain the input sequences, and and are their lengths. The array stores the last two rows of dynamic computations.
#define SIZE 1010 int x[SIZE], y[SIZE], mas[2][SIZE];
The main part of the program. Read the input sequences into the arrays, starting from the first index, i.e., into the cells and .
scanf("%d",&n); for(i = 1; i <= n; i++) scanf("%d",&x[i]); scanf("%d",&m); for(i = 1; i <= m; i++) scanf("%d",&y[i]);
Initialize the array with zeros.
memset(mas,0,sizeof(mas));
Compute the values of the function . Initially contains the values . Next, is used to store the values .
Since computing only requires the values from the previous row of the mas array, the values of can be stored in , the values of in and so on.
for(i = 1; i <= n; i++) for(j = 1; j <= m; j++) if (x[i] == y[j]) mas[i%2][j] = 1 + mas[(i+1)%2][j-1]; else mas[i%2][j] = max(mas[(i+1)%2][j],mas[i%2][j-1]);
Print the answer, which is stored in . The first argument is computed modulo .
printf("%d\n",mas[n%2][m]);
Algorithm implementation — recursion
#include <stdio.h> #include <string.h> #define SIZE 1002 int x[SIZE], y[SIZE], dp[SIZE][SIZE]; int n, m, i, j, res; int max(int i, int j) { return (i > j) ? i : j; } int lcs(int *x, int *y, int m, int n) { if (m == 0 || n == 0) return 0; if (dp[m][n] != -1) return dp[m][n]; if (x[m] == y[n]) return dp[m][n] = 1 + lcs(x, y, m - 1, n - 1); else return dp[m][n] = max(lcs(x, y, m, n - 1), lcs(x, y, m - 1, n)); } int main(void) { scanf("%d", &n); for (i = 1; i <= n; i++) scanf("%d", &x[i]); scanf("%d", &m); for (i = 1; i <= m; i++) scanf("%d", &y[i]); memset(dp, -1, sizeof(dp)); res = lcs(x, y, n, m); printf("%d\n", res); return 0; }
Java implementation
import java.util.*; public class Main { static int x[], y[], dp[][]; static int n, m; public static void main(String[] args) { Scanner con = new Scanner(System.in); n = con.nextInt(); x = new int[n+1]; for(int i = 1; i <= n; i++) x[i] = con.nextInt(); m = con.nextInt(); y = new int[m+1]; for(int i = 1; i <= m; i++) y[i] = con.nextInt(); dp = new int[2][m+1]; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) if (x[i] == y[j]) dp[i%2][j] = 1 + dp[(i-1)%2][j-1]; else dp[i%2][j] = Math.max(dp[(i-1)%2][j],dp[i%2][j-1]); System.out.println(dp[n%2][m]); con.close(); } }
Java implementation — recursion
import java.util.*; public class Main { static int x[], y[], dp[][]; static int n, m; public static int lcs(int m, int n) { if (m == 0 || n == 0) return 0; if (dp[m][n] != -1) return dp[m][n]; if (x[m] == y[n]) return dp[m][n] = 1 + lcs(m - 1, n - 1); else return dp[m][n] = Math.max(lcs(m, n - 1), lcs(m - 1, n)); } public static void main(String[] args) { Scanner con = new Scanner(System.in); n = con.nextInt(); x = new int[n+1]; for(int i = 1; i <= n; i++) x[i] = con.nextInt(); m = con.nextInt(); y = new int[m+1]; for(int i = 1; i <= m; i++) y[i] = con.nextInt(); dp = new int[n+1][m+1]; for(int i = 0; i <= n; i++) Arrays.fill(dp[i], -1); int res = lcs(n,m); System.out.println(res); con.close(); } }