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

-----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;
}

 

参考书籍:算法导论

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值