化为笔试中有这样的题目,如果用递归去做,运行时间为指数函数。用动态规划的方法去做,运行时间为O(mn).
java代码如下:
import java.util.*;
//请忽略类名及对象名,随手一起而而已,并没有什么特殊含义
public class Store{
public static void main(String[] args){
Store steel = new Store();
steel.init_m();
steel.F(7, 6);
//--打印出m表,便于分析------------------------------
System.out.print(" ");
for(int in = 0;in<6;in++){
System.out.print(steel.y[in] + " ");
}
System.out.println();
for(int i =1; i < 8; i++){
System.out.print(steel.x[i-1]+" ");
for(int j = 1; j < 7; j++){
System.out.print(steel.m[i][j] + " ");
}
System.out.println();
}
//--------------------------------------------
steel.reF(7, 6);
System.out.println("\n LCS的长度为: " + steel.m[7][6]);
}
private char[] x = {'a','b','c','b','d','a','b'};//7
private char[] y = {'b','d','c','a','b','a'};//6
private int[][] m = new int[8][7]; //储存子问题的结果
//初始化m表
private void init_m(){
for(int i = 0; i < 8; i++)
m[i][0]= 0;
for(int j = 0; j <7; j++)
m[0][j] = 0;
}
//自底向上的动态规划方法
private void F(int m, int n){
//以行为主次序
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
//因为x y 是从0开始的,所以才-1.
//如果 x y 的第一个元素相等,就把对应的m值+1
if(x[i-1] == y[j-1]){
this.m[i][j] = this.m[i-1][j-1]+1;
}
//否则,如果上面的值大于左边的值,把上面的值拿过来
else if(this.m[i-1][j] >= this.m[i][j-1]){
this.m[i][j] = this.m[i-1][j];
}
//否则,把下边的值拿过来
else
this.m[i][j] = this.m[i][j-1];
}
}
}
//用于重构LCS(最长公共子序列),可以对应着打印出来的m表来写这个函数
private void reF(int i, int j){
//防止越界
if(i == 0 || j == 0){
return ;
}
//对应于 F()函数。
//先考虑上面的值
if(this.m[i][j] == this.m[i-1][j]){
reF(i-1, j);
}
//再考虑左边的值
else if(this.m[i][j-1] == this.m[i][j]){
reF(i, j-1);
}
//前面的条件都不满足,那么此处的x[i-1](跟y[j-1]相等)就是我们想要的一个LCS的元素
else{
//打印出来的顺序是反着的
System.out.print(this.x[i-1] + " ");
reF(i-1, j-1);
}
}
}
输出结果:
b d c a b a
a 0 0 0 1 1 1
b 1 1 1 1 2 2
c 1 1 2 2 2 2
b 1 1 2 2 3 3
d 1 2 2 2 3 3
a 1 2 2 3 3 4
b 1 2 2 3 4 4
a b c b
LCS的长度为: 4
顺便用递归来解LCS长度问题的算法:
F(int i, int j)
if i == 0 or j == 0
return 0
if x(i) == y(j)
m(i,j) = F(i-1, j-1) + 1 //如果两个元素相等,问题就变x的子序列与y的子序列的问题了
else
return max(F(i, j-1), F(i-1, j)) //如果两个元素不相等,问题就变成两个子问题