字符串-最长公共子序列(LCS)

 

找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。

cnblogs与belong,最长公共子序列为blog(cnblogs, belong),最长公共子串为lo(cnblogs, belong)

这两个问题都是用空间换空间,创建一个二维数组来记录之前的每个状态.

最长公共子序列的状态转移方程:

分析参考:https://www.cnblogs.com/en-heng/p/3963803.html
               https://blog.csdn.net/ten_sory/article/details/79798064

这是经典的动态规划题目。

假设字符串 A=<x1,x2,⋯,xm> , B=<y1,y2,⋯,yn>

定义子问题dp[ i ][ j ]为字符串A的第一个字符到第 i 个(实际下标i-1)字符形成的字符串,即<x1,x2,⋯,xi>和字符串B的第一个字符到第 j(实际下标j-1) 个字符形成的字符串,即<y1,y2,⋯,yj>的最长公共子序列。

如A为“app”,B为“apple”,dp[ 2 ][ 3 ]表示 “ap” 和 “app” 的最长公共字串。注意到代码中 dp 的大小为 (n + 1) x (m + 1) ,这多出来的一行和一列是第 0 行和第 0 列,初始化为 0,表示空字符串和另一字符串的子串的最长公共子序列,例如dp[ 0 ][ 3 ]表示 “” 和 “app” 的最长公共字串。
当我们要求dp[ i ][ j ],我们要先判断A[ i-1 ]和B[ j-1 ]是否相同,如果相同他就是dp[ i - 1 ][ j - 1 ] + 1,相当于在两个字符串都去掉一个字符时的最长公共字串再加 1;否则最长公共字串取dp[ i ][ j - 1 ] 和dp[ i - 1 ][ j ] 中较大者。

class LCS {
public:
    int findLCS(string A, int n, string B, int m) {
        if(n<=0 || m<=0)
			return 0;
		vector<vector<int>> dp(n+1,vector<int>(m+1,0));
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				if(A[i-1]==B[j-1]) dp[i][j]=dp[i-1][j-1]+1;
				else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
		
		return dp[n][m];
    }
};

 

附加一个打印其中一个最长公共子序列的代码

附加: 输出其中一个最长公共子序列
// 还原如何求解dp的过程,具体看左神的p222
string solve(vector<vector<int>> &dp,n,m,string str1){
	
	char * res = new char[dp[n][m]];
	int index = dp[n][m]-1;
	while(index>=0){
		if(n>0 && dp[n][m]==dp[n-1][m]){
			--n;
		}else if(m>0 && dp[n][m]==dp[n][m-1]){
			--m;
		} else{
			res[index]=str1[n];
			--m;
			--n;
		}

	}
	
	string str = res;
	delete[] res;
	return str;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值