动态规划做最长公共子序列,最重要的是求出状态转移方程
理论的就不多说了,用语言太难描述了,直接去看视频吧!我们直接上代码。
对这里来说,他的状态转移方程如下
if(a[i - 1] == b[j - 1]){
c[i][j] = c[i - 1][j - 1] + 1;
d[i][j] = 1;
}
else if(c[i - 1][j] >= c[i][j - 1]){
c[i][j] = c[i - 1][j];
d[i][j] = 3;
}else{
c[i][j] = c[i][j - 1];
d[i][j] = 2;
}
源代码如下:
package DynamicPlan;
import java.util.Arrays;
public class MyComSub {
public static int ComSub(int [][]d,String s1,String s2){
char []a = s1.toCharArray();
char []b = s2.toCharArray();
int [][]c = new int[a.length + 1][b.length + 1];
for(int i = 1;i <= a.length;i++){
for(int j = 1;j <= b.length;j++){
//注意这里要减一,不然会超出数组长度错误
if(a[i - 1] == b[j - 1]){
c[i][j] = c[i - 1][j - 1] + 1;
d[i][j] = 1;
}
else if(c[i - 1][j] >= c[i][j - 1]){
c[i][j] = c[i - 1][j];
d[i][j] = 3;
}else{
c[i][j] = c[i][j - 1];
d[i][j] = 2;
}
}
}
return c[a.length][b.length];
}
//输出最长子序列
public static void Sub(int [][]d,String s1,int i,int j){
if(i == 0 || j ==0){
return;
}
//如果最优源来自左上方
if(d[i][j] == 1){
Sub(d,s1,i-1,j-1);
//注意要在这里输出,自己想想为什么
System.out.print(s1.charAt(i - 1));
//最优源来自最左边
}else if(d[i][j] == 2){
Sub(d,s1,i,j-1);
}{
//最优源来自上面
Sub(d, s1, i-1, j);
}
}
}
测试类的代码:注意这里的d数组是用来回溯用的
@Test
public void testComSub(){
String s1 = "abhshausci";
String s2 = "asjchauis";
//保存最优值的源 用于回溯出公共子序列
//1 表示来自当前元素的左上角
//2 表示来自当前元素的左边
//3 表示来自当前元素的上面
//注意创建矩阵的大小
int [][]d = new int[s1.length() + 1][s2.length() + 1];
int i = MyComSub.ComSub(d,s1,s2);
System.out.println(i);
for(int x = 0;x <d.length;x++){
for(int j = 0;j < d[i].length;j++){
System.out.printf("%d\t",d[x][j]);
}
System.out.println("\n");
}
MyComSub.Sub(d,s1.length() > s2.length()?s1:s2,s1.length(),s2.length());
}