最长公共子序列LCS

两个字符串S1与S2,求出其最长的公共子序列?
序列不同于子串,序列可以中间不连续,只要满足前后关系。
例如123456与13579,它们有最长的公共子序列135.

// 第一行 输入S1
// 第二行输入S2

动态规划解法

思路:
采用动态规划的解法,还是先制作一个二维表,找出其递推关系。
在这里插入图片描述
从表中可分析出:如果S1[i]=S2[j],则dp[i][j]=dp[i-1][j-1]+1;如果S1[i]!=S2[j],则dp[i][j]=max(dp[i-1][j],dp[i][j-1]),此即为状态转移方程。
但是此表只能计算出LCS的长度,要输出LCS串,我们还需要从右下角向左上依次找出相同字符,可能不止一个,此例中只找出一种。
代码:

#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
string s1,s2;
const int maxN=100;
int dp[maxN][maxN] ;

int main(){
	string res;
	int i,j,n1,n2;
	cin>>s1;
	cin>>s2;
	n1=s1.size();
	n2=s2.size();
	for(i=0;i<n1;i++){
		dp[i][0]=0;
	}
	for(j=0;j<n2;j++){
		dp[0][j]=0;
	}
	for(i=1;i<=n1;i++) {
		for(j=1;j<=n2;j++){
			if(s1[i-1]==s2[j-1])dp[i][j]=dp[i-1][j-1]+1;
			else{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
	}
	//到这里,只是求出LCS的长度,还要根据dp数组把串给找出来。
	cout<<dp[n1][n2]<<endl;//需要时可输出LCS长度值。 
	j=n2;//j值提前赋值,大循环中要用 
	for(i=n1;i>0;i--) {	//从最右下角 开始 
		if(dp[i][j]==dp[i-1][j])continue;
		//如果相等继续找上一行,找到不相等,继续在本行向左找 
		for(;j>0;j--){//j值使用前值,所以第一个分句不赋初值。 
			if(dp[i][j-1]!=dp[i][j])break;
		}//如果不相等,找到关键点,退出 ;如果相等,继续向左找 
		res=s1[i-1]+res;//取字符,插入前面 
		j--;//内循环提前结束,j要手动减1 
	}
	cout<<res<<endl;
	return 0;
}

深搜解法

思路:从S1中依次取出一个字符,与S2中从头到尾的字符比较,如果找到一个相同的,就把这个字符加到结果串中,然后再使用递归找两个剩余串的Lcs,再加到结果中。这时内循环就要退出,因为已使用递归了,不用再继续了。内循环结果后,找到一个结果,但要与当前最大公共子序列比较,只有超过它,才能取代它。如果找不到,结果就是空串。

#include <string>
#include <iostream>
using namespace std;
string s1,s2;
string dfs(string ss1,string ss2){
	int n1=ss1.size();
	int n2=ss2.size();
	int i,j;
	string maxans;
	string ans;
	for(i=0;i<n1;i++){
		ans="";
		for(j=0;j<n2;j++){
			if(ss1[i]==ss2[j]){//如果找到一个公共字符 
				ans=ans+ss1[i]//就把它加到结果中,再找两个剩余串的LCS 
				+dfs(ss1.substr(i+1,n1-i-1),ss2.substr(j+1,n2-j-1));
				break;//内循环结束 
			}
		}
		if(ans.size()>maxans.size())maxans=ans;
	}
	return maxans;
}
int main(){
	string re;
	cin>>s1;
	cin>>s2;
	re=dfs(s1,s2);
	cout<<re;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值