最长公共子序列(LCS)

来源:互联网 发布:费用优化方案 编辑:程序博客网 时间:2024/06/07 22:57
最长公共子序列LCS问题
       给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。给定X={x1, x2, …, xm}和Y = {y1, y2, …, yn},请找出X和Y的最长公共子序列。例如:
输入:X=ABCHFGASJKXBD           Y=DBDHASXB
输出:LCS=BHASXB
【分析】

       最长公共子序列LCS问题可用动态规划算法有效解决。而首先我们需要证明的是,使用动态规划算法的两个基本要素,即为什么最长公共子序列LCS问题可以用动态规划算法来解决。

最长公共子序列问题具有最优子结构性质:

       设序列X={x1,x2,x2,……,xm}Y={y1,y2,y3,……,yn},而Z={z1,z2,z3,……,zk}XY的最长公共子序列。则:

xm = yn,则zk = xm = ynZk-1Xm-1 Yn-1的最长公共子序列。

       (证:采用反证法,若zk != xm,那么有{z1,z2,z3,……,zk,xm}是为XY长度为k+1的最长公共子序列,这与ZXY长度为k的最长公共子序列矛盾。

       若Zk-1不是Xm-1Yn-1的最长公共子序列,则Xm-1Yn-1具有长度大于k-1的最长公共子序列,那么加上xm后,XY的最长公共子序列的长度应该大于k,这与ZXY长度为k的最长公共子序列矛盾。)

       若xm != yn 且 zk != xm,则ZXm-1Y的最长公共子序列。

       (证:采用反证法,若Z不是Xm-1Y的最长公共子序列,则Xm-1Y具有长度大于k的最长公共子序列,那么XY的最长公共子序列的长度必定也大于k。这与XY具有长度为k的最长公共子序列Z矛盾。)

xm != yn 且 zk != yn,则ZXYn-1的最长公共子序列。

       (证:采用反证法,证法同上述类似)


      最长公共子序列问题具有子问题重叠性质。

在寻找XY的最长公共子序列时,我们要进行分类讨论:

xm = yn时,我们要找出Xm-1Yn-1的最长公共子序列,在其尾部加上xm就为XY的最长公共子序列;

xm != yn时,我们要找出 Xm-1Y的最长公共子序列和XYn-1的最长公共子序列,再比较两者哪个大,即为XY的最长公共子序列。

       我们可以从中看出,当我们要查找Xm-1Y的最长公共子序列时,同样也要按照上面所说的步骤进行查找,即有可能要继续查找Xm-2YXm-1Yn-1的最长公共子序列;当我们要XYn-1的最长公共子序列时,同样也要按照上面所说的步骤进行查找,即有可能要继续查找Xm-1Yn-1XYn-2的最长公共子序列。在这两个子问题都包含了一个公共子问题,即计算Xm-1Yn-1的最长公共子序列。

 

       建立LCS问题的递推关系,用c[i][j]表示XiYj的最长公共子序列的长度。其中Xi={x1,x2,……,xi}Yj={y1,y2,……,yj}

c[i][j] = 0,   i = j = 0;

c[i][j] = c[i - 1][j - 1] + 1,   xi = yj;

c[i][j] = max{c[i - 1][j], c[i][j - 1]},   xi != yj;

根据递推关系,我们可以写出程序。

【程序】
用java语言编写程序,代码如下:

import java.io.BufferedInputStream;import java.util.Scanner;public class LCS {public static void main(String[] args) {Scanner input = new Scanner(new BufferedInputStream(System.in));while(input.hasNext()) {int m = input.nextInt();String sx = input.next();char[] x = new char[m + 1];for(int i = 1; i < m + 1; i++)x[i] = sx.charAt(i - 1);int n = input.nextInt();String sy = input.next();char[] y = new char[n + 1];for(int i = 1; i < n + 1; i++)y[i] = sy.charAt(i - 1);/*int[][] c = new int[m + 1][n + 1];for(int i = 0; i < m + 1; i++)for(int j = 0; j < n + 1; j++)c[i][j] = -1;int len = LCS(m, n, x, y, c);System.out.println();System.out.println(len);*/int[][] c = new int[m + 1][n + 1];int[][] b = new int[m + 1][n + 1];LCSlength(m, n, x, y, c, b);printLCS(m, n, b, x);System.out.println();System.out.println(c[m][n]);}}/*public static int LCS(int m, int n, char[] x, char[] y, int[][] c) {if(m == 0 || n == 0) {c[m][n] = 0;return 0;}//if(c[m][n] != -1)//return c[m][n];if(x[m] == y[n]) {c[m][n] = LCS(m - 1, n - 1, x, y, c) + 1;System.out.print(x[m]);System.out.println(m + " " + n);}else {int lcs1 = LCS(m, n - 1, x, y, c);int lcs2 = LCS(m - 1, n, x, y, c);if(lcs1 > lcs2)c[m][n] = lcs1;elsec[m][n] = lcs2;}return c[m][n];}*/public static void LCSlength(int m, int n, char[] x, char[] y, int[][] c, int[][] b) {int i, j;for(i = 1; i <= m; i++)c[i][0] = 0;for(j = 1; j <= n; j++)c[0][j] = 0;for(i = 1; i <= m; i++)for(j = 1; j <= n; 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] = 2;}else {c[i][j] = c[i][j - 1];b[i][j] = 3;}}}}public static void printLCS(int i, int j, int[][] b, char[] x) {if(i == 0 || j == 0)return;if(b[i][j] == 1) {printLCS(i - 1, j - 1, b, x);System.out.print(x[i]);}else if(b[i][j] == 2)printLCS(i - 1, j, b, x);elseprintLCS(i, j - 1, b, x);}}

0 0
原创粉丝点击