打印最长公共子序列
给定两个序列,打印它们中存在的最长子序列。
例子:
输入序列“ABCDGH”和“AEDFHR”的 LCS 是长度为 3 的“ADH”。
输入序列“AGGTAB”和“GXTXAYB”的 LCS 是长度为 4 的“GTAB”。
我们在上一篇文章中讨论了最长公共子序列(LCS)问题。那里讨论的函数主要是找到 LCS 的长度。为了找到 LCS 的长度,构建了一个 2D 表 L[][]。在这篇文章中,讨论了构建和打印 LCS 的函数。
以下是打印 LCS 的详细算法。它使用相同的 2D 表 L[][]。
1)使用上一篇文章中讨论的步骤构造 L[m+1][n+1]。
2)值 L[m][n] 包含 LCS 的长度。创建一个长度等于 lcs 长度加 1 的字符数组 lcs[](存储 \0 的额外一个)。
2)从 L[m][n] 开始遍历二维数组。对每个单元格 L[i][j] 执行以下操作
..... a)如果对应于 L[i][j] 的字符(在 X 和 Y 中)相同(或 X[i-1] == Y[j-1]),则将此字符作为 LCS 的一部分包含在内.
..... b)否则比较 L[i-1][j] 和 L[i][j-1] 的值,然后朝着更大的值方向前进。
下表(取自 Wiki)显示了上述算法的步骤(突出显示)。 0 1 2 3 4 5 6 7 Ø M Z J A W X U 0 Ø 0 0 0 0 0 0 0 0 1 X 0 0 0 0 0 0 1 1 2 M 0 1 1 1 1 1 1 1 3 J 0 1 1 2 2 2 2 2 4 Y 0 1 1 2 2 2 2 2 5 A 0 1 1 2 3 3 3 3 6 U 0 1 1 2 3 3 3 4 7 Z 0 1 2 2 3 3 3 4
以下是上述方法的实现。
C++
/* Dynamic Programming implementation of LCS problem */
#include
#include
#include
using namespace std;
/* Returns length of LCS for X[0..m-1], Y[0..n-1] */
void lcs( char *X, char *Y, int m, int n )
{
int L[m+1][n+1];
/* Following steps build L[m+1][n+1] in bottom up fashion. Note
that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */
for (int i=0; i<=m; i++)
{
for (int j=0; j<=n; j++)
{
if (i == 0 || j == 0)
L[i][j] = 0;
else if (X[i-1] == Y[j-1])
L[i][j] = L[i-1][j-1] + 1;
else
L[i][j] = max(L[i-1][j], L[i][j-1]);
}
}
// Following code is used to print LCS
int index = L[m][n];
// Create a character array to store the lcs string
char lcs[index+1];
lcs[index] = '\0'; // Set the terminating character
// Start from the right-most-bottom-most corner and
// one by one store characters in lcs[]
int i = m, j = n;
while (i > 0 && j > 0)
{
// If current character in X[] and Y are same, then
// current character is part of LCS
if (X[i-1] == Y[j-1])
{
lcs[index-1] = X[i-1]; // Put current character in result
i--; j--; index--; // reduce values of i, j and index
}
// If not same, then find the larger of two and
// go in the direction of larger value
else if (L[i-1][j] > L[i][j-1])
i--;
else
j--;
}
// Print the lcs
cout << "LCS of " << X << " and " << Y << " is " << lcs;
}
/* Driver program to test above function */
int main()
{
char X[] = "AGGTAB";
char Y[] = "GXTXAYB";
int m = strlen(X);
int n = strlen(Y);
lcs(X, Y, m, n);
return 0;
}
Java
// Dynamic Programming implementation of LCS problem in Java
import java.io.*;
class LongestCommonSubsequence
{
// Returns length of LCS for X[0..m-1], Y[0..n-1]
static void lcs(String X, String Y, int m, int n)
{
int[][] L = new int[m+1][n+1];
// Following steps build L[m+1][n+1] in bottom up fashion. Note
// that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
for (int i=0; i<=m; i++)
{
for (int j=0; j<=n; j++)
{
if (i == 0 || j == 0)
L[i][j] = 0;
else if (X.charAt(i-1) == Y.charAt(j-1))
L[i][j] = L[i-1][j-1] + 1;
else
L[i][j] = Math.max(L[i-1][j], L[i][j-1]);
}
}
// Following code is used to print LCS
int index = L[m][n];
int temp = index;
// Create a character array to store the lcs string
char[] lcs = new char[index+1];
lcs[index] = '\u0000'; // Set the terminating character
// Start from the right-most-bottom-most corner and
// one by one store characters in lcs[]
int i = m;
int j = n;
while (i > 0 && j > 0)
{
// If current character in X[] and Y are same, then
// current character is part of LCS
if (X.charAt(i-1) == Y.charAt(j-1))
{
// Put current character in result
lcs[index-1] = X.charAt(i-1);
// reduce values of i, j and index
i--;
j--;
index--;
}
// If not same, then find the larger of two and
// go in the direction of larger value
else if (L[i-1][j] > L[i][j-1])
i--;
else
j--;
}
// Print the lcs
System.out.print("LCS of "+X+" and "+Y+" is ");
for(int k=0;k<=temp;k++)
System.out.print(lcs[k]);
}
// driver program
public static void main (String[] args)
{
String X = "AGGTAB";
String Y = "GXTXAYB";
int m = X.length();
int n = Y.length();
lcs(X, Y, m, n);
}
}
// Contributed by Pramod Kumar
Python3
# Dynamic programming implementation of LCS problem
# Returns length of LCS for X[0..m-1], Y[0..n-1]
def lcs(X, Y, m, n):
L = [[0 for x in range(n+1)] for x in range(m+1)]
# Following steps build L[m+1][n+1] in bottom up fashion. Note
# that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
for i in range(m+1):
for j in range(n+1):
if i == 0 or j == 0:
L[i][j] = 0
else if X[i-1] == Y[j-1]:
L[i][j] = L[i-1][j-1] + 1
else:
L[i][j] = max(L[i-1][j], L[i][j-1])
# Following code is used to print LCS
index = L[m][n]
# Create a character array to store the lcs string
lcs = [""] * (index+1)
lcs[index] = ""
# Start from the right-most-bottom-most corner and
# one by one store characters in lcs[]
i = m
j = n
while i > 0 and j > 0:
# If current character in X[] and Y are same, then
# current character is part of LCS
if X[i-1] == Y[j-1]:
lcs[index-1] = X[i-1]
i-=1
j-=1
index-=1
# If not same, then find the larger of two and
# go in the direction of larger value
else if L[i-1][j] > L[i][j-1]:
i-=1
else:
j-=1
print ("LCS of " + X + " and " + Y + " is " + "".join(lcs) )
# Driver program
X = "AGGTAB"
Y = "GXTXAYB"
m = len(X)
n = len(Y)
lcs(X, Y, m, n)
# This code is contributed by BHAVYA JAIN
C#
// Dynamic Programming implementation
// of LCS problem in C#
using System;
class GFG
{
// Returns length of LCS for X[0..m-1], Y[0..n-1]
static void lcs(String X, String Y, int m, int n)
{
int[,] L = new int[m+1, n+1];
// Following steps build L[m+1][n+1] in
// bottom up fashion. Note that L[i][j]
// contains length of LCS of X[0..i-1]
// and Y[0..j-1]
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
L[i, j] = 0;
else if (X[i-1] == Y[j-1])
L[i, j] = L[i-1, j-1] + 1;
else
L[i, j] = Math.Max(L[i-1, j], L[i, j-1]);
}
}
// Following code is used to print LCS
int index = L[m, n];
int temp = index;
// Create a character array
// to store the lcs string
char[] lcs = new char[index+1];
// Set the terminating character
lcs[index] = '\0';
// Start from the right-most-bottom-most corner
// and one by one store characters in lcs[]
int k = m, l = n;
while (k > 0 && l > 0)
{
// If current character in X[] and Y
// are same, then current character
// is part of LCS
if (X[k-1] == Y[l-1])
{
// Put current character in result
lcs[index-1] = X[k-1];
// reduce values of i, j and index
k--;
l--;
index--;
}
// If not same, then find the larger of two and
// go in the direction of larger value
else if (L[k-1, l] > L[k, l-1])
k--;
else
l--;
}
// Print the lcs
Console.Write("LCS of " + X + " and " + Y + " is ");
for(int q = 0; q <= temp; q++)
Console.Write(lcs[q]);
}
// Driver program
public static void Main ()
{
String X = "AGGTAB";
String Y = "GXTXAYB";
int m = X.Length;
int n = Y.Length;
lcs(X, Y, m, n);
}
}
// This code is contributed by Sam007
PHP
0 && $j > 0)
{
// If current character in X[] and Y are same,
// then current character is part of LCS
if ($X[$i - 1] == $Y[$j - 1])
{
// Put current character in result
$lcs[$index - 1] = $X[$i - 1];
$i--;
$j--;
$index--; // reduce values of i, j and index
}
// If not same, then find the larger of two
// and go in the direction of larger value
else if ($L[$i - 1][$j] > $L[$i][$j - 1])
$i--;
else
$j--;
}
// Print the lcs
echo "LCS of " . $X . " and " . $Y . " is ";
for($k = 0; $k < $temp; $k++)
echo $lcs[$k];
}
// Driver Code
$X = "AGGTAB";
$Y = "GXTXAYB";
$m = strlen($X);
$n = strlen($Y);
lcs($X, $Y, $m, $n);
// This code is contributed by ita_c
?>
Javascript
输出:
LCS of AGGTAB and GXTXAYB is GTAB