动态规划----最长公共子序列LCS

原创 2016年08月28日 18:08:01
1、基本概念

  一个给定序列的子序列就是该给定序列中去掉零个或者多个元素的序列。形式化来讲就是:给定一个序列X={x1,x2,……,xm},另外一个序列Z={z1、z2、……,zk},如果存在X的一个严格递增小标序列<i1,i2……,ik>,使得对所有j=1,2,……k,有xij = zj,则Z是X的子序列。例如:Z={B,C,D,B}是X={A,B,C,B,D,A,B}的一个子序列,相应的小标为<2,3,5,7>。从定义可以看出子序列直接的元素不一定是相邻的。

公共子序列:给定两个序列X和Y,如果Z既是X的一个子序列又是Y的一个子序列,则称序列Z是X和Y的公共子序列。例如:X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A},则序列{B,C,A}是X和Y的一个公共子序列,但不不是最长公共子序列。

最长公共子序列(LCS)问题描述:给定两个序列X={x1,x2,……,xm}和Y={y1,y2,……,yn},找出X和Y的最长公共子序列。

2、动态规划解决过程

1)描述一个最长公共子序列

  如果序列比较短,可以采用蛮力法枚举出X的所有子序列,然后检查是否是Y的子序列,并记录所发现的最长子序列。如果序列比较长,这种方法需要指数级时间,不切实际。

  LCS的最优子结构定理:设X={x1,x2,……,xm}和Y={y1,y2,……,yn}为两个序列,并设Z={z1、z2、……,zk}为X和Y的任意一个LCS,则:

(1)如果xm=yn,那么zk=xm=yn,而且Zk-1是Xm-1和Yn-1的一个LCS。

  (2)如果xm≠yn,那么zk≠xm蕴含Z是是Xm-1和Yn的一个LCS。

  (3)如果xm≠yn,那么zk≠yn蕴含Z是是Xm和Yn-1的一个LCS。

  定理说明两个序列的一个LCS也包含两个序列的前缀的一个LCS,即LCS问题具有最优子结构性质。

2)一个递归解

  根据LCS的子结构可知,要找序列X和Y的LCS,根据xm与yn是否相等进行判断的,如果xm=yn则产生一个子问题,否则产生两个子问题。设C[i,j]为序列Xi和Yj的一个LCS的长度。如果i=0或者j=0,即一个序列的长度为0,则LCS的长度为0。LCS问题的最优子结构的递归式如下所示:



源代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int b[100][100];//方便求最优解
char c[100][100];

void LCS_LENGTH(char *X, char *Y)
{
	int m = strlen(X);
	int n = strlen(Y);
	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 = 0; i < m; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			if (X[i] == Y[j])
			{
				c[i+1][j+1] = c[i][j] + 1;
				b[i+1][j+1] = 0;
			}
			else if (c[i, j+1] >= c[i+1, j])
			{
				c[i+1][j+1] = c[i][j+1];
				b[i+1][j+1] = 1;
			}
			else
			{
				c[i+1][j+1] = c[i+1][j];
				b[i+1][j+1] = -1;
			}
		}
	}
}

void PRINT_LCS(char *x, int i, int j)
{
	if (i == 0 || j == 0)
		return;
	if (b[i][j] == 0)
	{
		PRINT_LCS(x, i - 1, j - 1);
		printf("%c ", x[i - 1]);
	}
	else if (b[i][j] == 1)
		PRINT_LCS(x, i - 1, j);
	else
		PRINT_LCS(x, i, j - 1);
}

int main()
{
	char X[] = "BDCABA";
	char Y[] = "ABCBDAB";
	LCS_LENGTH(X, Y);
	

	printf("%d\n", c[strlen(X)][strlen(Y)]);
	PRINT_LCS(X, strlen(X), strlen(Y));
	printf("\n%s %s\n", __DATE__, __TIME__);
	system("pause");
	return 0;
}

运行结果:

4
B D A B
Aug 28 2016 18:05:18
请按任意键继续. . .





版权声明:本文为博主原创文章,未经博主允许不得转载。

《github一天一道算法题》:动态规划法解决最长公共子序列(LCS)问题的最简单方法

/* * copyleft@hustyangju * 问题:longest common subsequece problem * 思路:从底往上,利用动态规划,划分子问题,利用LCS子问题的长...

动态规划(dynamic program)&& 最长公共子序列(LCS)

动态规划特征: 1.最优子结构

动态规划解最长公共子序列问题(LCS)C语言加注释

【问题】 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,...

0011算法笔记——【动态规划】最长公共子序列问题(LCS)

问题描述:一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切地说,若给定序列X= { x1, x2,…, xm},则另一序列Z= {z1, z2,…, zk}是X的子序列是指存在一...

动态规划——最长公共子序列问题(LCS)

动态规划——最长公共子序列问题(LCS) 最长公共子序列问题(LCS)。给两个子序列A和B,如图9-7所示。求长度最大的公共子序列。例如1, 5, 2, 6, 8, 7和2, 3, 5, 6, 9...

Java实现算法导论中最长公共子序列(LCS)动态规划法

1、问题: 求两字符序列的最长公共字符子序列LCS 2、求解:动态规划法                      动态规划的思路就是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是...

算法导论学习笔记(十二):动态规划(二):最长公共子序列(LCS)

LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了。公共部分 必须是以相同的顺序出现,但是不必要是连续的。 解法一:在没学动态规划之前,...

动态规划经典之求最长公共子序列LCS

题目描述: 给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共...

动态规划求解最长公共子序列(LCS)

看了《算法导论》中文第二版P208的动态规划求解LCS问题,觉得很赞,但总觉得算导写得有些晦涩,希望自己能写得简单易懂一些,纯当锻炼了,欢迎指导交流。 首先,子序列和子串是不一样的。子串是连续的,而子...

动态规划算法解最长公共子序列LCS问题

动态规划算法解LCS问题 作者 July 二零一零年十二月三十一日 本文参考:微软面试100题系列V0.1版第19、56题、算法导论、维基百科。 第一部分、什么是动态规划算法 ok,咱们先来...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:动态规划----最长公共子序列LCS
举报原因:
原因补充:

(最多只允许输入30个字)