标签:style blog http color java ar strong for 2014
问题描述:序列X={x1,x2,…,xn},Y={y1,y2,…,yn},当Z={z1,z2…,zn}是X的严格递增下标顺序(可以不连续)的子集,也是Y的严格递增下标顺序(可以不连续)的子集,则Z是X和Y的公共子序列。例如X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A},{B,C,A}、{B,C,B,A}、{B,D,A,B}都是X和Y的公共子序列。其中最长的公共子序列叫做Longest common subsequence,即经典的LCS。
具体点:char[]xArray和char[] yArray是字符数组,长度分别为m、n,求他们的LCS
【分析】自顶向下分析,二维数组cTable[i][j]记录xArray[0~i],yArray[0~j]的最长公共子序列的长度,则cTable[m][n]记录xArray[0~m],yArray[0~n]的最长公共子序列的长度。
1) 如果xArray[m]=yArray[n],表明最后一个元素xArray[m]是LCS中的元素,xArray[0~m],yArray[0~n]的最长公共子序列=xArray[0~m-1],yArray[0~n-1]的最长公共子序列+1,即cTable[m][n]=cTable[m-1][n-1]。
2) 如果xArray[m]!=yArray[n],表明xArray[m]、yArray[n]都有可能是LCS中的元素,但不能同时是。如果xArray[m]可能是,则xArray[0~m],yArray[0~n]的最长公共子序列=xArray[0~m],yArray[0~n-1]的最长公共子序列;如果yArray[n]可能是,则xArray[0~m],yArray[0~n]的最长公共子序列=xArray[0~m-1],yArray[0~n]的最长公共子序列。即cTable[m][n]=max(cTable[m-1][n],
cTable[m][n-1])。
状态递归方程为:
参考《算法导论》P394页伪代码,java实现如下:
-
-
-
- public static
void main(String[] args) {
-
- String x="ABCBDABCBACABC";
- String y="BDCABACABABCB";
- int temp=getLCSLength(x, y);
- System.out.println("\n长度为:"+temp);
- }
- public static
int getLCSLength(String x,String y) {
- char[] xArray=x.toCharArray();
- char[] yArray=y.toCharArray();
- int m=xArray.length;
- int n=yArray.length;
- int [][] bTable=new
int[m][n];
-
- int [][] cTable=new
int[m+1][n+1];
- for (int i =
0; i <m; i++) {
- for (int j =
0; j < n; j++) {
- if (xArray[i]==yArray[j]) {
- cTable[i+1][j+1]=cTable[i][j]+1;
- bTable[i][j]=2;
- }else if (cTable[i][j+1]>=cTable[i+1][j]) {
- cTable[i+1][j+1]=cTable[i][j+1];
- bTable[i][j]=1;
- }else {
- cTable[i+1][j+1]=cTable[i+1][j];
- bTable[i][j]=3;
- }
-
- }
-
- }
- System.out.print("最大子数组为:");
- printLCS(xArray, bTable, m-1,n-1);
- return cTable[m][n];
- }
-
- public static
void printLCS (char[] xArray,int[][] bTable,int i,int
j) {
- if (i==-1||j==-1) {
- return;
- }
- if (bTable[i][j]==2) {
- printLCS(xArray, bTable, i-1, j-1);
- System.out.print(xArray[i]);
- }else if (bTable[i][j]==1) {
- printLCS(xArray, bTable, i-1, j);
- }else {
- printLCS(xArray, bTable, i, j-1);
- }
- }
-
- }
/**
* 创建时间:2014年9月3日 下午9:00:13
* 项目名称:Test
* @author Cao Yanfeng Peking University
* @since JDK 1.6.0_21
* 类说明: 最长公共子序列问题(Longest common subsequence,LCS)
*/
public static void main(String[] args) {
// TODO 自动生成的方法存根
String x="ABCBDABCBACABC";
String y="BDCABACABABCB";
int temp=getLCSLength(x, y);
System.out.println("\n长度为:"+temp);
}
public static int getLCSLength(String x,String y) {
char[] xArray=x.toCharArray();
char[] yArray=y.toCharArray();
int m=xArray.length;
int n=yArray.length;
int [][] bTable=new int[m][n];
/*cTable[i][j]记录xArray[0~i],yArray[0~j]的最长公共子序列的长度*/
int [][] cTable=new int[m+1][n+1];
for (int i = 0; i <m; i++) {
for (int j = 0; j < n; j++) {
if (xArray[i]==yArray[j]) {
cTable[i+1][j+1]=cTable[i][j]+1;
bTable[i][j]=2;//相等标记为2
}else if (cTable[i][j+1]>=cTable[i+1][j]) {
cTable[i+1][j+1]=cTable[i][j+1];
bTable[i][j]=1;
}else {
cTable[i+1][j+1]=cTable[i+1][j];
bTable[i][j]=3;
}
}
}
System.out.print("最大子数组为:");
printLCS(xArray, bTable, m-1,n-1);
return cTable[m][n];
}
/*输出最佳路径即最长公共子序列*/
public static void printLCS (char[] xArray,int[][] bTable,int i,int j) {
if (i==-1||j==-1) {
return;
}
if (bTable[i][j]==2) {
printLCS(xArray, bTable, i-1, j-1);
System.out.print(xArray[i]);
}else if (bTable[i][j]==1) {
printLCS(xArray, bTable, i-1, j);
}else {
printLCS(xArray, bTable, i, j-1);
}
}
}
*****************************************
控制台输出:
最大子数组为:BCBACBACB
长度为:9
【算法导论学习-29】动态规划经典问题02:最长公共子序列问题(Longest common subsequence,LCS)
标签:style blog http color java ar strong for 2014
原文地址:http://blog.csdn.net/weitao1234/article/details/39181205