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

问题描述

字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。
令给定的字符序列X=(x0,x1,…,xm-1),序列Y=(y0,y1,…,yk-1)是X的子序列,存在X的一个严格递增下标序列(i0,i1,…,ik-1),使得对所有的j=0,1,…,k-1,有 =yj。

问题求解

若设A=(a0,a1,…,am-1)(含m个字符),B=(b0,b1,…,bn-1)(含n个字符),设Z=(z0,z1,…,zk-1)(含k个字符)为它们的最长公共子序列。不难证明有以下性质:
如果am-1=bn-1,则zk-1=am-1=bn-1,且(z0,z1,…,zk-2)是(a0,a1,…,am-2)和(b0,b1,…,bn-2)的一个最长公共子序列。
如果am-1≠bn-1且zk-1≠am-1,则(z0,z1,…,zk-1)是(a0,a1,…,am-2)和(b0,b1,…,bn-1)的一个最长公共子序列。
如果am-1≠bn-1且zk-1≠bn-1,则(z0,z1,…,zk-1)是(a0,a1,…,am-1)和(b0,b1,…,bn-2)的一个最长公共子序列。
定义二维动态规划数组dp,其中dp[i][j]为子序列(a0,a1,…,ai-1)和(b0,b1,…,bj-1)的最长公共子序列的长度。
每考虑字符a[i]或b[j]都为动态规划的一个阶段(共经历约m×n个阶段)。
在这里插入图片描述
在这里插入图片描述
对应的状态转移方程如下:
在这里插入图片描述
显然,dp[m][n]为最终结果。
当dp[i][j] ≠ dp[i][j-1](左边)并且dp[i][j] ≠ dp[i-1][j](上方)值时:a[i-1]=b[j-1]将a[i-1]添加到LCS中。
dp[i][j]=dp[i][j-1]:与左边相等 j–
dp[i][j]=dp[i-1][j]:与上方相等 i–
与左边、上方都不相等:a[i-1]或者b[j-1]属于LCS i–,j–

代码

int m, n;
string a, b;
int dp[MAXN][MAXN];
vector<char> subs;
void LCSlength()
{
	int i, j;
	for (i = 0; i <= m; i++)
		dp[i][0] = 0;
	for (j = 0; j <= n; j++)
		dp[0][j] = 0;
	for (i = 1; i <= m; i++)
	{
		for (j = 1; j <= n; j++)
		{
			if (a[i - 1] == b[j - 1])
				dp[i][j] = dp[i - 1][j - 1] + 1;
			else
				dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
		}
	}
}

void Buildsubs()
{
	int k = dp[m][n];
	int i = m;
	int j = n;

	while (k > 0)
	{
		if (dp[i][j] == dp[i - 1][j])
			i--;
		else if (dp[i][j] == dp[i][j - 1])
			j--;
		else
		{
			subs.push_back(a[i - 1]);
			i--; j--; k--;
		}
	}
}

算法分析

LCSlength算法中使用了两重循环,所以对于长度分别为m和n的序列,求其最长公共子序列的时间复杂度为O(m×n)。空间复杂度为O(m×n)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值