算法:Common Subsequence(动态规划 Java 最长子序列)
Description
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
Input
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
Output
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
Sample Input
abcfbc abfcab
programming contest
abcd mnp
Sample Output
4
2
0
求最大子序列的问题:
递推关系:c[][]存储最长子序列长度
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1, str2;
while (sc.hasNext()){
str1 = sc.next();
str2 = sc.next();
System.out.println(LcsLength(str1.toCharArray(), str2.toCharArray()));
}
sc.close();
}
public static int LcsLength(char a[], char b[]){
int aL = a.length;
int bL = b.length;
int ans[][] = new int[aL + 1][bL + 1];
for (int i = 0; i <= aL; i++) {
ans[i][0] = 0;
}
for (int i = 0; i <= bL; i++) {
ans[0][i] = 0;
}
for (int i = 1; i <= aL; i++) {
for (int j = 1; j <= bL; j++) {
if (a[i - 1] == b[j - 1])
ans[i][j] = ans[i - 1][j - 1] + 1;
else if (ans[i][j - 1] >= ans[i - 1][j])
ans[i][j] = ans[i][j - 1];
else
ans[i][j] = ans[i - 1][j];
}
}
return ans[aL][bL];
}
}
可以输出最长子序列之一的代码:
import java.util.Scanner;
public class Main {
public static int x[][];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1, str2;
while (sc.hasNext()) {
str1 = sc.next();
str2 = sc.next();
System.out.println("最大子序列长度: " + LcsLength(str1.toCharArray(), str2.toCharArray()));
}
sc.close();
}
public static int LcsLength(char a[], char b[]) {
int aL = a.length; // a数组的长度
int bL = b.length; // b数组的长度
int ans[][] = new int[aL + 1][bL + 1]; // 存储i,j当前的最长子序列长度
x = new int[aL + 1][bL + 1]; // 存储ans[i][j]是斜对角还是左边,上边来的
for (int i = 0; i <= aL; i++) {
ans[i][0] = 0; // 空的子序列都为0
}
for (int i = 0; i <= bL; i++) {
ans[0][i] = 0; // 空的子序列都为0
}
for (int i = 1; i <= aL; i++) {
for (int j = 1; j <= bL; j++) {
if (a[i - 1] == b[j - 1]) { // 判断字符是否相等
ans[i][j] = ans[i - 1][j - 1] + 1; // 相等长度加1
x[i][j] = 1; // 标记为相等斜着来的
} else if (ans[i][j - 1] >= ans[i - 1][j]) { // 左边大于上边就用最大的
ans[i][j] = ans[i][j - 1];
x[i][j] = 2; // 标记为左边来的
} else {
ans[i][j] = ans[i - 1][j];
x[i][j] = 3; // 标记为上边来的
}
}
}
System.out.print("最大子序列: ");
Lcs(aL, bL, a);
System.out.print('\n');
return ans[aL][bL];
}
// 递归输出最大子序列其中一个
public static void Lcs(int i, int j, char a[]) {
if (i == 0 || j == 0)
return;
if (x[i][j] == 1) {
Lcs(i - 1, j - 1, a);
System.out.print(a[i - 1]);
} else if (x[i][j] == 2)
Lcs(i, j - 1, a);
else if (x[i][j] == 3)
Lcs(i - 1, j, a);
}
}