动态规划-最长公共子序列
算法思想:动态规划
实际问题:最长公共子序列
编写语言:Java
问题描述
子序列:是一个给定序列的子序列是在该序列中删去若干元素后得到的序列。如X={A, B, C, D}, {A, C}是X的子序列,{A, B, D}是X的子序列。
问题描述:给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列,X和Y的所有公共子序列中长度最长的即是X和Y的最长公共子序列。
值得一提的是,最长公共子序列不只一个,但构造的时候只能构造出一个。
关键特征
设序列X={x1, x2, x3, …, xm}和Y={y1, y2, y3, …, yn}的最长公共子序列为Z={z1, z2, z3, …, zk},则:
- 若xm=yn, 则zk=xm=yn, 且Zk-1是Xm-1和Yn-1的最长公共子序列
- 若xm!=yn, 且zk!=xm, 则Z是Xm-1和Y的最长公共子序列
- 若xm!=yn, 且zk!=yn, 则Z是X和Yn-1的最长公共子序列
其中:Xm-1={x1, x2, …, xm-1},Yn-1={y1, y2, …, yn-1},Zk-1={z1, z2, …, zk-1}。
递归结构
用c[i][j]记录序列Xi和Yj的最长公共子序列长度,那么:
- 当i=0, j=0时,c[i][j]=0
- 当i>0, j>0, xi=yj时,c[i][j] = c[i-1][j-1]+1
- 当i>0, j>0,xi!=yj时,c[i][j] = max{c[i][j-1], c[i-1][j]}
其中,第3点是说当xm!=yn时,求取Xm-1, Y和X, Yn-1两者的最长公共子序列的较长者作为整体的最长公共子序列
Java代码
public class LongestCommonSubsequence
{
public static void main(String[] args)
{
//第一个字符留空,可以省去后续很多麻烦
char[] x = new char[]{' ', 'A', 'B', 'C', 'B', 'D', 'A', 'B'};
char[] y = new char[]{' ', 'B', 'D', 'C', 'A', 'B', 'A'};
int m = x.length;
int n = y.length;
int[][] c = new int[m][n];
int[][] b = new int[m][n];
lcsLength(m - 1, n - 1, x, y, c, b);
lcs(m - 1, n - 1, x, b); //从m-1,n-1开始往下面找
System.out.println();
}
/**
* 参数含义:
* m: X序列的长度
* n: Y序列的长度
* x, y: 待求最长公共子序列的原始序列
* c: 记录Xi和Yj的最长公共子序列长度
* b: 记录得到c[i][j]的是哪个子问题
*/
public static void lcsLength(int m, int n, char[] x, char[] y,
int[][] c, int[][] b)
{
for(int i = 0; i < m; i++)
c[i][0] = 0;
for(int i = 0; i < n; i++)
c[0][i] = 0;
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
{
if(x[i] == y[j])
{
c[i][j] = c[i - 1][j - 1] + 1;
b[i][j] = 1;
}
else if(c[i-1][j] > c[i][j - 1])
{
c[i][j] = c[i - 1][j];
b[i][j] = 2;
}
else
{
c[i][j] = c[i][j - 1];
b[i][j] = 3;
}
}
}
}
/**
* 该方法构造一个X,Y的最长公共子序列
* 参数含义:
* i, j: 序列X, Y的下标
* x: 原始序列,因为构造的是X, Y的最长公共子序列。
* 此处用Y也行,因为x有的y也有。
* 但是序列应全程保持一致(一开始用X,整个函数都用X)
* b: 用于构造子序列的二维数组
*/
public static void lcs(int i, int j, char[] x, int[][] b)
{
if(i == 0 || j == 0)
return;
if(b[i][j] == 1)
{
lcs(i - 1, j - 1, x, b);
System.out.print(x[i] + " ");
}
else if(b[i][j] == 2)
lcs(i - 1, j, x, b);
else
lcs(i, j - 1, x, b);
}
}