Найбільша спільна підпослідовність#1618

Найбільша спільна підпослідовність (Розбір)

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 \{2, 1, 3, 5\}. Then

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 \{1, 2, 3\} and \{2, 1, 3, 5\} can be or . In this case, the length of the LCS is .

Let f(i, j) be the length of the longest common subsequence of the sequences x_1x_2 \ldots x_i and y_1y_2 \ldots y_j.

If x_i \ne y_j, the LCS should be found among two options:

Return the maximum of these values:

f(i, j) = max( f(i, j – 1), f(i – 1, j) )

If x_i = y_j, add the current element x_i to the LCS and consider the shorter prefixes x_1x_2 \ldots x_{i-1} and y_1y_2 \ldots y_{j-1}:

f(i, j) = 1 + f(i – 1, j – 1)

If one of the sequences is empty, then their LCS is also empty:

f(0, j) = f(i, 0) = 0

The recurrence relation for computing the LCS length is as follows:

f(i, j) = \begin{cases} max(f(i, j - 1), f(i - 1, j)), x_i \ne y_j \\ f(i - 1, j - 1) + 1, x_i = y_j\\ 0, i = 0~or~j = 0 \end{cases}

Let’s consider an example of the calculations:

The values of f(i, j) will be stored in an array , where m[0][i] = m[i][0] = 0. 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 X = abcdgh, Y = aedfhr. The longest common subsequence is , and its length is f(6, 6) = 3.

f(6, 6) = max(f(6, 5), f(5, 6)) = max(2, 3) = 3, because Y[6] = r ≠ h = X[6].

f(5, 6) = 1 + f(4, 5) = 1 + 2 = 3, because Y[5] = h = X[6].

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];

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 f(i, j). Initially mas[0][j] contains the values f(0, j) = 0. Next, mas[1][j] is used to store the values f(1, j).

Since computing f(2, j) only requires the values from the previous row of the mas array, the values of f(2, j) can be stored in mas[0][j], the values of f(3, j) in mas[1][j] 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();
  }
}

Python implementation

Read the input sequences into lists and .

n = int(input())
x = [0] + list(map(int, input().split()))

m = int(input())
y = [0] + list(map(int, input().split()))

Initialize the list , which contains the last two rows of the dynamic transformation.

dp = [[0] * (m + 1) for _ in range(2)]

Compute the values of f(i, j)~(1 \le i \le n, 1 \le j \le m). Store the results of f(i, j) in the cells dp[i \% 2][j].

for i in range(1, n + 1):
  for j in range(1, m + 1):
    if x[i] == y[j]:
      dp [i % 2][j] = dp[(i - 1) % 2][j - 1] + 1
    else:
      dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[i % 2][j - 1])

Print the result, which is located in the cell . The first argument is computed modulo .

print(dp[n % 2][m])