又到了本宝宝讲故事的时间辣!好吧并不是什么好故事。。。话说成天A题能找到老婆吗!没关系我老婆是电脑……诶。。。←这句话不是我说的
还是看题吧,模板题不记录一下会很不爽,这是初级的LCS题,就是只需要算出最大公共子序列的元素个数就行了!
那么接下来说一下这道题需要用到的LCS知识点吧!
LCS,就是最大公共子序列,给你两个字符串,其中相同的最长的两个字符串都含有的子序列就是我们要求的结果。注意这里面说的子序列是不要求连续的。
举栗子说,有 abcfc 和 abfcab 两个字符串,那么他们的LCS就是 abfc ,这就告诉我们尽管abfc对于abcfc中间少了一个c,但它仍然是abcfc的子序列。
要想求LCS,遍历不用想一定超时,怎么办?动态规划来解决!
首先我们需要一个二维数组dp[na][nb],na是第一个字符串的字符数,n2是第二个字符串的字符数,哎呀空说不行,还要举例子!
比如说现在有 abcfc 和 abfcab 两个字符串,要求最大公共子序列的元素个数,咋弄咧,由于说建立了一个二维的dp数组,我们将其用表格来呈现!
咱们规定每个字符串下标从1开始,所以第二行和第二列都是0,表示跳过字符串数组第一个符号。
但是这里会出现一个问题,就是字符串数组第一个元素如果是空着的话,会被自动填充为'\0',用strlen()函数读取字符串长度时,遇到的第一个'\0'就是0号元素,读取长度是0,咋弄呢?根据题意,在读取完字符串时再给两个字符串的0号元素一个题中明显没有的符号就行了。
好,下面介绍表格内容:第一行是字符串a的每个元素,第一列是字符串b的每个元素,中间空着的地方用来存放当检查到当前格子时,最大公共子串所含有的元素个数。
好神奇,原理是什么?
首先要注意这种算法后面的数据是要根据前面推得的,而且要同时遍历两个字符串元素。
我们知道每个格子记录的是最大公共子串所含有的元素个数,什么意思?就比方说图中第5行第5列来讲(下面出现的坐标都表示第几行第几列,比如string那一格坐标是(1,1)而不是(0,0)),这里面如果有数字,那么这里面的数字就代表根据字符串 abc 和 abf 这两个字符串所找到的最大公共子列的元素个数。
我们设定i和j分别表示坐标,(i,j)表示第i行第j列的空格。
这种算法是这样工作的:先设定第2行与第2列都是0,因为不管检查到哪里,字符串的每个元素都不跟a[0] or b[0]匹配,所以此时最大元素子串都是0。好,现在设定双重循环,针对这张图,外循环i初始是3,内循环j初始值是3,a[3]与b[3]都是a,好,匹配!这时候需要在上一个已经找到的最大公共子串数字基础上加一!阿列,这是找到的第一个?没事,那就当上一个最大公共子列元素个数是0就好啦,实际上上一个最大公共子列是dp[i-1][j-1]中所储存的数据,就是当前格子左上方那个格子所储存的数据。所以dp(3,3)就是dp(2,2)+1,就是1啦。下面来到dp(3,4),很明显a[3]与b[4]不匹配,呀,咋弄?废话,既然匹配失败了,当然最大公共子串元素个数不会增加了,那么当前格子数字应该填什么?当然是上一个最大dp值了~注意,此时最大的上一个dp值有两个情况,一个是dp[i-1][j]可能是最大的,也有可能是dp[i][j-1],就是上面那个格子的值或者是左边的那个,上面那个我们刚刚填过,有可能是最大的,左边那个因为长度检查到了b串当前元素的上一个元素,如果那个元素与a串匹配了,那么左边那个也有可能是最大的数,所以我们直接在这两个格子中选较大的值填入当前格子就OK了,这样一直循环到每个字符串的最后一个元素,那么dp最后一个元素就是我们要找的最大子串的值了(图中最大的值的坐标是(7,8))
这个表格填完以后是这样的:
好啦,格子填完了,答案也就出来了,想要详细理解的可以再看看介个视频:十分钟搞定LCS
下面上题!
【题目】
Time Limit: 1000MS | Memory Limit: 10000K | |
xxxxxxxxxxxxxxx | xxxxxxxxxxxxxxxxxx |
Description
Input
Output
Sample Input
abcfbc abfcab programming contest abcd mnp
Sample Output
4 2 0
【题意】
给你两个字符串,求最大公共子串的元素个数
输入:两个字符串,中间用空格隔开,处理到EOF
输出:最大公共子串元素个数,输出占一行
【思路】
求解过程上面说过了,要注意如果想让字符串第一个元素下标是1,scanf的时候要取a[1]的地址,还有如果这样做的话别忘了设定下标为0的元素值不为‘\0’哦!还有这样的话计算字符串的长度的时候第0号元素会被计算在内,别忘了减一。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[1005],b[1005];
int dp[1005][1005];
int main()
{
while(scanf("%s%s",&a[1],&b[1])!=EOF)//这样取地址是为了设置第一个元素下标为 1
{
a[0]='!';
b[0]='@';//别忘了设置第0个元素内容不是'\0'!
int na=strlen(a)-1;
int nb=strlen(b)-1;//这样做会多算一个长度(第0号元素多被计算在内)所以要减一
memset(dp,0,sizeof(dp));
for(int i=1;i<=na;i++)//核心代码,填写表格
{
for(int j=1;j<=nb;j++)
{
if(a[i]==b[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
printf("%d\n",dp[na][nb]);
}
}
这篇博客我写了快两个小时了,手要废了。。。TAT 看我这么辛苦,你就点一下下面那个赞吧,没错就是下面那个!
还有点击我头像下面的“+加关注”就可以关注我了,以后发表有趣的文章的时候会有提醒哦~嗯?你不要点一下吗,点一下不花钱的~真的!