最长公共子序列(LCS)

1.定义

给定两个序列X和Y,如果序列Z既是X的子序列,也是Y的子序列,我们称Z是X和Y的公共子序列(common subsequence)。

2.定理(LCS的最优子结构)

令 X = {x1, x2, x3, ..., xm} 和 Y = {y1, y2, y3, ..., yn} 为两个序列, Z = {z1, z2, z3, ..., zk} 为 X 和 Y 的任意LCS。

1. 如果xm = yn , 则 zk = xm = yn 且 Zk-1 是 Xm-1 和 Y n-1 的一个LCS

2. 如果xm != yn ,那么 zk != xm 意味着 Z 是Xm-1 和 Yn-1 的一个LCS

3. 如果xm != yn ,那么 zk != yn 意味着Z是X和Yn-1的一个LCS

3.公式

若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]);

4.代码(java实现)

public class LCS {
	
	public static void main(String[] args) {
		String[] X = {"A", "B", "C", "B", "D", "A", "B", "B", "A", "C"};
		String[] Y = {"B", "D", "C", "A", "B", "A", "A", "B", "C"};
//		print_Array(LCS_length(X, Y));
		print_LCS(LCS_length(X, Y), X, X.length, Y.length);
	}
	
	/**
	 * @param X
	 * @param Y
	 * @return 子问题的最优解
	 */
	private static String[][] LCS_length(String[] X, String[] Y) {
		int m = X.length;
		int n = Y.length;
		String[][] b = new String[m + 1][n + 1];	//存放子问题的最优解
		int[][] c = new int[m + 1][n + 1];	//子问题最优解长度
		for (int i = 0; i <= m; i++) {
			c[i][0] = 0;
		}
		for (int j = 0; j <= n; j++) {
			c[0][j] = 0;
		}
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= n; j++) {
				if(X[i - 1] == Y[j - 1]) {
					c[i][j] = c[i - 1][j - 1] + 1;
					b[i][j] = "↖";
				} else if(c[i - 1][j] >= c[i][j - 1]) {
					c[i][j] = c[i - 1][j];
					b[i][j] = "↑";
				} else {
					c[i][j] = c[i][j - 1];
					b[i][j] = "←";
				}
			}
		}
		return b;
	}
	
	/**
	 * 递归打印LCS
	 */
	private static void print_LCS(String[][] b, Object[] X, int i, int j) {
		if(i == 0 || j == 0) {
			return;
		}
		if(b[i][j].equals("↖")) {
			print_LCS(b, X, i - 1, j - 1);
			System.out.print(X[i - 1] + " ");
		} else if (b[i][j].equals("↑")) {
			print_LCS(b, X, i - 1, j);
		} else {
			print_LCS(b, X, i, j - 1);
		}
	}
	
	private static void print_Array(String[][] b) {
		for (int i = 0; i < b.length; i++) {
			for (int k = 0; k < b[i].length; k++) {
				
				System.out.print(b[i][k] + "   ");
			}
			System.out.println();
		}
	}
}

5.代码运行结果

B C B A B C 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值