package org.loda.dynamic;
import org.junit.Test;
/**
*
* @ClassName: LCS
* @Description: 最长公共子序列
*
* 动态规划问题
*
* @author minjun
* @date 2015年5月19日 上午10:48:57
*
*/
public class LCS {
@Test
public void lcs() {
String a = "BDCABA";
String b = "ABCBDAB";
// 利用二维数组记录最长公共子序列
String[][] sub = new String[a.length() + 1][b.length() + 1];
// 求a,b最长公共子序列长度
int len = lcs(a, b, sub);
System.out.println(a + "和" + b + "的最长公共子序列长度为:" + len);
// 打印获取最长子序列的回溯轨迹
printRoute(a, b, sub);
// 获取最长公共子序列
String lcs = requireLCS(a, b, sub);
System.out.println("a,b串的其中一个最长公共子序列为:" + lcs);
}
private void printRoute(String a, String b, String[][] sub) {
for (int i = 1; i <= a.length(); i++) {
for (int j = 1; j <= b.length(); j++) {
System.out.print(sub[i][j] + "\t");
}
System.out.println();
}
}
private String requireLCS(String a, String b, String[][] sub) {
StringBuilder sb = new StringBuilder();
int i = a.length();
int j = b.length();
//按照标记的箭头回溯路径,并记录当箭头为↖的字符(属于公共子序列的字符)
while (i > 0 && j > 0) {
if ("↖".equals(sub[i][j])) {
sb.append(a.charAt(i - 1));
i--;
j--;
} else if ("←".equals(sub[i][j])) {
j--;
} else if ("↑".equals(sub[i][j])) {
i--;
}
}
return sb.reverse().toString();
}
private int lcs(String a, String b, String[][] sub) {
int lenA = a.length();
int lenB = b.length();
// c[i][j]表示子序列a1->ai和子序列b1->bj的最长公共子序列长度
// 并且在c矩阵中,a字符串作为竖排字符串,b作为横排字符串,a的长度作为行数,b的长度作为列数
int[][] c = new int[lenA + 1][lenB + 1];
// c[0][x]和c[x][0]表示有一个子序列长度为0,那么两个的公共子序列长度必然也是0
// 由于java中整形数组中元素默认值就是0,所以可以省略,这里为了描述算法思想,手动设置为0
for (int i = 0; i < lenA + 1; i++) {
c[i][0] = 0;
}
for (int j = 0; j < lenB + 1; j++) {
c[0][j] = 0;
}
for (int i = 1; i <= lenA; i++) {
// 获取字符串a的第i个元素
char chA = a.charAt(i - 1);
for (int j = 1; j <= lenB; j++) {
// 获取字符串b
char chB = b.charAt(j - 1);
//利用算法导论中的公式求解
if (chA == chB) {
c[i][j] = c[i - 1][j - 1] + 1;
sub[i][j] = "↖";
} else {
if (c[i - 1][j] <= c[i][j - 1]) {
c[i][j] = c[i][j - 1];
sub[i][j] = "←";
} else {
c[i][j] = c[i - 1][j];
sub[i][j] = "↑";
}
}
}
}
return c[lenA][lenB];
}
}
输出内容:
BDCABA和ABCBDAB的最长公共子序列长度为:4
← ↖ ← ↖ ← ← ↖
← ↑ ← ← ↖ ← ←
← ↑ ↖ ← ← ← ←
↖ ← ↑ ← ← ↖ ←
↑ ↖ ← ↖ ← ← ↖
↖ ↑ ← ↑ ← ↖ ←
a,b串的其中一个最长公共子序列为:BCBA