程序设计与算法----动态规划之最长上升子序列

问题描述

给出两个字符串,求出这样的一个最长的公共子序列的长度:子序列中的每个字符都能在两个原串中找到,而且每个字符的先后顺序和原串中的顺序一致。
样例输入

abcfbc abfcab
programming contest
abcd mnp

样例输出

4
2
0

算法思想

输入两个串s1,s2,设MaxLen(I,j)表示:
s1左边的第i个字符形成的子串,与s2左边的j个字符形成的子串的最长公共子序列的长度(i,j从0开始算)

MaxLen(i,j)就是本题的状态。
假定len1=strlen(s1),len2=strlen(s2)
那么题目就是要求MaxLen(len1,len2)
显然:
MaxLen(n,0)=0(n=0…len1)
MaxLen(0,n)=0(n=0…len2)

递推公式:
if(s1[i-1]==s2[j-1]) //s1的最左边字符时s1[0]
MaxLen(i,j)= MaxLen(i-1,j-1)+1

(s1的左边形成的i个字符和s2的左边j个字符所形成的最长公共子序列的长度等于s1左边的i-1个字符和s2左边的j-1个字符所形成的最长公共子序列的长度+1)
else
MaxLen(i,j)=Max(MaxLen(i,j-1), MaxLen(i-1,j))

(s1左边的i个字符和s2的左边j-1个字符,s1左边的i-1个字符和s2左边的j个字符所形成的公共子序列的长度的最大值)
时间复杂度O(mn)m,n是两个子串长度
在这里插入图片描述

s1[i-1]!=s2[j-1],maxlen(s1,s2)不会比maxlen(s1,s2j-1)和maxlen(s1i-1,s2)两者汇总的任何一个小,也不会比两者都大。
前者,显然成立。
对于后者,反证法,假设maxlen(s1,s2)比maxlen(s1,s2j-1)大,它们的差别在于前者比后者多了一个字符,多出来的字符时s2[j-1],说明s2[j-1]要起作用,说明它是属于他们的最长公共子序列,maxlen(s1,s2)比maxlen(s1i-1,s2)大,同理,s1[i-1]起作用,它必然是s1和s2所形成的最长公共子序列的字符,所以s1[i-1]和s2[j-1]均是s1和s2最长公共子序列的最后一个字符。与前提矛盾,说明前面的假设不成立,
则s1[i-1]!=s2[j-1],maxlen(s1,s2)不会比maxlen(s1,s2j-1)和maxlen(s1i-1,s2)两者汇总的任何一个小,也不会比两者都大。

程序代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXSIZE 100
char a[MAXSIZE];
char b[MAXSIZE];
int maxLen[MAXSIZE][MAXSIZE];
int commonStr(char a [ ],char b [ ]){
	//计算两个字符串的长度 
	int len_a=strlen(a);
	int len_b=strlen(b);
	int i,j;
	//设置边界条件
	for(i=0;i<=len_b;i++){
		 maxLen[len_a][0]=0;
	}
	for(i=0;i<=len_a;i++){
		 maxLen[0][len_b]=0;
	}
	for(i=0;i<len_a;i++){
		for(j=0;j<len_b;j++){
			//当a[i]等于b[j] 
			//s1的左边形成的i个字符和s2的左边j个字符所形成的最长公共子序列的长度等于
			//s1左边的i-1个字符和s2左边的j-1个字符所形成的最长公共子序列的长度+1 
			if(a[i]==b[j]){
				maxLen[i+1][j+1]=maxLen[i][j]+1;
			}else{
				//当a[i]不等于b[j]时 
				//s1左边的i个字符和s2的左边j-1个字符,s1左边的i-1个字符和s2左边的j个字符所形成的公共子序列的长度的最大值
				maxLen[i+1][j+1]=max(maxLen[i][j+1],maxLen[i+1][j]);
			}
		}
	} 
	return maxLen[len_a][len_b];
}
int main(){
	int *res=new int[MAXSIZE];
	int num=0;
	while(cin>>a>>b){
		res[num++]=commonStr(a,b);
	}
	for(int i=0;i<num;i++){
		cout<<res[i]<<endl;
	}
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值