词条 | 最长公共子序列 |
释义 | 问题描述最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。 应用最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。简而言之,百度知道、百度百科都用得上。 算法动态规划的一个计算两个序列的最长公共子序列的方法如下: 以两个序列 X、Y 为例子: 设有二维数组 f[i,j] 表示 X 的 i 位和 Y 的 j 位之前的最长公共子序列的长度,则有: f[1][1] = same(1,1); f[i,j] = max{f[i-1][j -1] + same(i,j),f[i-1,j],f[i,j-1]} 其中,same(a,b)当 X 的第 a 位与 Y 的第 b 位完全相同时为“1”,否则为“0”。 此时,f[j]中最大的数便是 X 和 Y 的最长公共子序列的长度,依据该数组回溯,便可找出最长公共子序列。 该算法的空间、时间复杂度均为O(n^2),经过优化后,空间复杂度可为O(n)。 代码(Pascal)const maxlen=200; var i,j :longint; c :array[0..maxlen,0..maxlen] of byte; x,y,z :string; {z为x,y的最长公共子序列} begin readln(x); readln(y); fillchar(c,sizeof(c),0); for i:=1 to length(x) do for j:=1 to length(y) do if x[i]=y[j] then c[i,j]:=c[i-1,j-1]+1 else if c[i-1,j]>c[i,j-1] then c[i,j]:=c[i-1,j] else c[i,j]:=c[i,j-1]; z:=''; i:=length(x); j:=length(y); writeln(c[i,j]); while (i>0) and (j>0) do if x[i]=y[j] then begin z:=x[i]+z;i:=i-1;j:=j-1 end else if c[i-1,j]>c[i,j-1] then i:=i-1 else j:=j-1; if z<>'' then writeln(z); for i:=1 to length(x) do begin for j:=1 to length(y) do write(c[i][j]:3); writeln; end; readln; end. 代码(C++)#include <cstdlib> #include <iostream> using namespace std; #define N 105 int dp[N+1][N+1] ; char str1[N] , str2[N]; int maxx(int a , int b) { if(a > b) return a ; return b ; } int LCSL(int len1 , int len2) { int i , j ; int len = maxx(len1 , len2); for( i = 0 ; i <= len; i++ ) { dp[i][0] = 0 ;dp[0][i] = 0 ; } for( i = 1 ; i<= len1 ; i++) for( j = 1 ; j <= len2 ; j++) { if(str1[i - 1] == str2[j - 1]) { dp[i][j] = dp[i - 1][ j - 1] + 1 ; } else { dp[i][j] = maxx(dp[i - 1][ j ] , dp[i][j - 1]) ; } } return dp[len1][len2]; } int main() { while(cin >> str1 >> str2) { int len1 = strlen(str1) ; int len2 = strlen(str2) ; cout<<LCSL(len1 , len2)<<endl; } return 0; } Java 代码public class LCSProblem { public static void main(String[] args) { String[] x = {"", "A", "B", "C", "B", "D", "A", "B"}; String[] y = {"", "B", "D", "C", "A", "B", "A"}; int[][] b = getLength(x, y); Display(b, x, x.length-1, y.length-1); } public static int[][] getLength(String[] x, String[] y) { int[][] b = new int[x.length][y.length]; int[][] c = new int[x.length][y.length]; for(int i=1; i<x.length; i++) { for(int j=1; j<y.length; j++) { if( x[i] == y[j]) { c[i][j] = c[i-1][j-1] + 1; b[i][j] = 1; } else if(c[i-1][j] >= c[i][j-1]) { c[i][j] = c[i-1][j]; b[i][j] = 0; } else { c[i][j] = c[i][j-1]; b[i][j] = -1; } } } return b; } public static void Display(int[][] b, String[] x, int i, int j) { if(i == 0 || j == 0) return; if(b[i][j] == 1) { Display(b, x, i-1, j-1); System.out.print(x[i] + " "); } else if(b[i][j] == 0) { Display(b, x, i-1, j); } else if(b[i][j] == -1) { Display(b, x, i, j-1); } } } |
随便看 |
百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。