关闭

最长公共子序列

1524人阅读 评论(2) 收藏 举报
分类:

原理
动态规划方法解LCS问题的原理如下:
考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…,am-1”,B=“b0,b1,…,bn-1”,并Z=“z0,z1,…,zk-1”为它们的最长公共子序列。不难证明有以下性质:
(1) 如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一个最长公共子序列;
(2) 如果am-1!=bn-1,则若zk-1!=am-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列;
(3) 如果am-1!=bn-1,则若zk-1!=bn-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列。
这样,在找A和B的公共子序列时,如有am-1=bn-1,则进一步解决一个子问题,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一个最长公共子序列;如果am-1!=bn-1,则要解决两个子问题,找出“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列和找出“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列,再取两者中较长者作为A和B的最长公共子序列。


引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。

问题的递归式写成:

recursive formula

回溯输出最长公共子序列过程:

flow

 

算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m * n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m * n)。

实现代码:

public class LCP {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String one = " " + "ABCBDAB";
		String two = " " + "BDCABA";

		char x[] = one.toCharArray();
		char y[] = two.toCharArray();

		int b[][] = getLength(x, y);

		myprint(b, x, x.length - 1, y.length - 1);
	}

	private static void myprint(int[][] b, char[] x, int i, int j) {

		if (i == 0 || j == 0) {
			return;
		}

		if (b[i][j] == 0) {
			myprint(b, x, i - 1, j - 1);
			System.out.print(x[i] + " ");
		} else if (b[i][j] == 1) {
			myprint(b, x, i - 1, j);
		} else {
			myprint(b, x, i, j - 1);
		}

	}

	private static int[][] getLength(char[] x, char[] y) {
		// TODO Auto-generated method stub
		int b[][] = new int[x.length][y.length];
		int c[][] = new int[x.length][y.length];

		for (int i = 1; i < x.length; i++) {
			for (int j = 1; j < y.length; j++) {
				if (x[i] == y[j]) {
					c[i][j] = c[i - 1][j - 1] + 1;
					b[i][j] = 0; // 左上角继承
				} else if (c[i - 1][j] >= c[i][j - 1]) {
					c[i][j] = c[i - 1][j];
					b[i][j] = 1; // 上方继承
				} else {
					c[i][j] = c[i][j - 1];
					b[i][j] = 2; // 左方继承
				}
			}
		}

		return b;
	}

}
测试结果:


2
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

动态规划 最长公共子序列 过程图解

1.基本概念       首先需要科普一下,最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。什么是子序...
  • hrn1216
  • hrn1216
  • 2016-05-29 22:54
  • 41523

最长公共子序列(LCS)

1、LCS基本概念          子序列:一个序列X任意删除若干个字符得到新序列Z,则Z叫做X的子序列。例如Z=是X=B,C,B,D,A,B>的子序列,相当于删除A、B、A。         ...
  • DQ_DM
  • DQ_DM
  • 2015-04-14 16:18
  • 7618

【动态规划】输出所有的最长公共子序列

上篇讲到使用动态规划可以在 θ(mn) 的时间里求出 LCS 的长度,本文将讨论如何输出最长公共子序列。 问题描述:给定两个序列,例如 X = “ABCBDAB”、Y = “BDCABA”,求它们的最...
  • lisong694767315
  • lisong694767315
  • 2014-11-29 15:41
  • 6902

C++实现最长公共子序列和最长公共子串

转载自:点击打开链接 #include "stdafx.h" #include #include using namespace::std; int lcs(string str1, st...
  • chengonghao
  • chengonghao
  • 2016-07-14 21:36
  • 5759

最长公共子序列理解心得之C/C++

今天在在做腾讯2017年暑期实习生编程题的时候遇到的求最长回文串个数,其中遇到了一个知识点,求最长公共子序列。 下面看一下百科给出的解释: 再看看算法与应用: 求公共子序列举例:...
  • no_sying_nothing
  • no_sying_nothing
  • 2016-08-12 01:22
  • 592

最长公共子序列(LCS)

本来这篇文章是想直接转载过来一篇,然后看看就行了,但是个人总觉得看别人的不如自己动手写过的理解好,所以还是决定把理解的过程记录下来。LCS问题:首先先知道LCS问题,这有两种: 1.Longest ...
  • tingyun_say
  • tingyun_say
  • 2016-08-30 22:09
  • 818

最长公共上升子序列

最长公共上升子序列
  • u011396840
  • u011396840
  • 2014-08-13 16:04
  • 1784

最长公共子序列Java代码实现

最长公共子序列定义:两个或多个已知数列的子序列集合中最长的就是最长公共子序列。 比如数列A = “abcdef”和B = “adefcb”,那么两个数列的公共子序列集合有{”a","ab","abc...
  • fjssharpsword
  • fjssharpsword
  • 2016-07-19 11:08
  • 6277

算法分析与设计实验 动态规划法 求最长公共子序列

实验目的   加深对动态规划法的算法原理及实现过程的理解,学习用动态规划法解决实际应用中的 最长公共子序列问题。 实验内容   内容: 用动态规划法实现求两序列的最长公共子序列,其比较结果可用于基因比...
  • wyh7280
  • wyh7280
  • 2015-05-07 18:18
  • 1449

动态规划之最长公共子序列问题 C++实现

动态规划之最长公共子序列问题 C++实现原理在之前的文章当中,作者论述了设么事动态规划,这次,我们来看看,如何用动态规划解决最长公共子序列问题。这个问题经常运用在判断两种生物的相似度—-DNA比对上。...
  • liu798675179
  • liu798675179
  • 2016-11-08 12:12
  • 1031
    个人资料
    • 访问:44025次
    • 积分:1615
    • 等级:
    • 排名:千里之外
    • 原创:120篇
    • 转载:11篇
    • 译文:0篇
    • 评论:4条
    最新评论