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

原创 2012年03月21日 15:27:57

-----Edit by ZhuSenlin HDU

求最长公共子序列。给定两个序列 ,希望找出X和Y的最大公共子序列。

1) 确定LCS最优子结构。设为X和Y的任意一个LCS,则

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

如果xm!=yn,那么zk!=xm蕴含Z是Xm-1和Y的一个LCS;

如果xm!=yn,那么zk!=yn蕴含Z是X和Yn-1的一个LCS

2) 寻找递归解

设C[i,j]为序列Xi和Yj的一个LCS的长度。则

                        

3) 计算长度

创建一个表Table存放每一个(i,j)对应的LCS的长度。则C[Length(X)][Length(Y)]为X与Y的LCS长度。

创建另外一个表Path记录路径,如果则Path[i][j]=’x’(斜),如果则Path[i][j]=’u’(up),如果则Path[i][j]=’l’(left)。

 

代码如下:

template <class T>
void CreateTable(T**& pTable, int nH, int nW)
{
	DeleteTable(pTable,nH);
	pTable = new T* [nH];
	for(int i = 0; i < nH; i++)	{
		pTable[i] = new T[nW];
		memset(pTable[i],0,nW*sizeof(T));
	}
}

template <class T>
void DeleteTable(T**& pTable, int nH)
{
	if(!pTable)
		return;
	for(int i = 0; i < nH; i++)
		if(pTable[i])
			delete pTable[i];
	delete pTable;
}

int LengthLCS(const char* pStrA, const char* pStrB, int**& pTable, char**& pPath)
{
	int nLengthA = strlen(pStrA);
	int nLengthB = strlen(pStrB);
	for(int i = 1; i<= nLengthA; i++){
		for(int j = 1; j <= nLengthB; j++) {
			if(pStrA[i-1] == pStrB[j-1]) {
				pTable[i][j] = pTable[i-1][j-1]+1;
				pPath[i][j] = 'x';
			}
			else if(pTable[i-1][j] < pTable[i][j-1]){
				pTable[i][j] = pTable[i][j-1];
				pPath[i][j] = 'l';
			}
			else {
				pTable[i][j] = pTable[i-1][j];
				pPath[i][j] = 'u';
			}
		}
	}
	return pTable[nLengthA][nLengthB];
}

void PrintLCS(char** pPath, const char* pStrA,int nLengthA, int nLengthB)
{
	if(nLengthA == 0 || nLengthB == 0)
		return;
	if(pPath[nLengthA][nLengthB] == 'x') {
		PrintLCS(pPath, pStrA, nLengthA-1, nLengthB-1);
		cout << pStrA[nLengthA-1] << " ";
	}
	else if(pPath[nLengthA][nLengthB] == 'l')
		PrintLCS(pPath,pStrA,nLengthA,nLengthB-1);
	else
		PrintLCS(pPath,pStrA,nLengthA-1,nLengthB);
}

测试代码如下:

int main()
{
	const char* pStrA = "abcbdab";
	const char* pStrB = "bdcaba";
	int** pTable = NULL;
	char** pPath = NULL;
	int nLengthA = strlen(pStrA);
	int nLengthB = strlen(pStrB);
	CreateTable(pTable,nLengthA+1,nLengthB+1);
	CreateTable(pPath,nLengthA+1,nLengthB+1);

	cout << LengthLCS(pStrA,pStrB,pTable,pPath) << endl;
	PrintLCS(pPath,pStrA,strlen(pStrA),strlen(pStrB));
	cout << endl;

	DeleteTable(pTable,strlen(pStrA)+1);
	DeleteTable(pPath,strlen(pStrA)+1);
	return 0;
}

 

参考书籍:算法导论

LCS算法的两种JAVA实现方式

给定字符串A,B Solution  I: 1.构造数组 c i  j 描述A串的前i位和B串的前J位的LCS长度 2.构造数组 trace  i  j  描述max相应位置得到的长度是由哪一步得出的...
  • Lyz1052
  • Lyz1052
  • 2015年06月14日 12:39
  • 693

LCS问题,JAVA实现

本文参照July的博客,第十一章,只给出个人理解和java实现
  • kringpin_lin
  • kringpin_lin
  • 2014年06月25日 20:49
  • 941

LCS算法的C++实现

最长公共子序列LCS的C++实现
  • zmq570235977
  • zmq570235977
  • 2015年11月15日 15:02
  • 1664

【动态规划】LCS算法:求两字符串最大公共字符串(连续)

LCS算法的应用 问题描述:求两字符串的连续最大公共子字符串 思路:根据上文LCS算法求解两字符串的最大公共子序列(不连续),可以得到求解连续子字符串的启示,如图所示,构造LCS矩阵vec,将两个...
  • yebanxin
  • yebanxin
  • 2016年08月12日 12:46
  • 1791

动态规划之LCS和LIS

(一)最长公共子序列 (二)dai
  • Netown_Ethereal
  • Netown_Ethereal
  • 2014年04月18日 14:44
  • 2175

LCS(最长公共子序列)和dp(动态规划)

参照:v_JULY_v        最长公共子序列定义:         注意最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subs...
  • u011479875
  • u011479875
  • 2015年04月30日 12:15
  • 973

最长公共子序列LCS递归解法

#include #include using namespace std; int row,col,**map,index,maxLen; char *record,*lcs; bool flag=...
  • lc0817
  • lc0817
  • 2015年03月17日 13:51
  • 2009

动态规划和递归求lcs

代码如下 #include #include #include using namespace std; int data[2000][2000]; string a = "3741a169n084...
  • u011915028
  • u011915028
  • 2016年05月15日 22:29
  • 369

动态规划-最长公共子字符串(LCS)

学习算法导论,看到动态规划的LCS,于是用C++将算法实现。 编程实现的过程中要特别注意**边界条件**和算法导论书上的实现有出入的地方,否则会出现**数组越界**和**LCS统计不完整**的问题。...
  • YanceyZ_DL
  • YanceyZ_DL
  • 2016年04月18日 16:48
  • 358

LCS 最长公共子序列并输出该序列

#include #include #include #include #include #include #include using namespace std; string s1...
  • u013573047
  • u013573047
  • 2014年08月13日 17:17
  • 940
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:动态规划——最长公共子序列(LCS)
举报原因:
原因补充:

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