版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/82222137
思路:题目意思很好懂,就是求s1的前缀和s2的后缀的最长公共长度;下面两种解法
1.把s1当成字串,s2当成母串,问题就变成了典型的扩展kmp算法问题,只不过要注意,扩展kmp求的ex[i]代表s2[i...len-1]和s1 最长的公共前缀的长度 ,也就是说ex[i]只是s2后缀的前缀字串,而题目要求的是s2的后缀,所以只有当ex[i]+i==s2_len的时候才是正确的答案;
2.把两个字串拼接一下,问题就变成了求s前缀和后缀的最长公共长度,也就是kmp算法中next数组,但是仍然需要注意的是,next数组求得的数据,前缀有可能包含了s2,后缀有可能包含了s1,所以答案必须是小于其中两者小的的长度,也就是原本应该输出next的最后一个数据,而现在应该是对next的不断进行递归,直到小于其中两者小的的长度;
如果对kmp算法和扩展kmp算法有所疑惑的读者,可以参考以下两篇大牛的文章:
扩展kmp算法:
https://segmentfault.com/a/1190000008663857
kmp算法:
https://blog.csdn.net/v_july_v/article/details/7041827
kmp算法的ac代码:
#include <stdio.h>
#include <iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#define maxx 100000+10
using namespace std;
int nex[maxx];
void getnext(char *s)
{
int slen = strlen(s);
int j = 0;
nex[0] = -1;
int k = -1;
while (j < slen)
{
if (k == -1 || s[k] == s[j])
{
k++, j++;
nex[j] = k;
}
else
k = nex[k];
}
}
int main()
{
char s1[maxx], s2[maxx];
while (scanf("%s%s", s1, s2) != EOF)
{
int s1len = strlen(s1);
int s2len = strlen(s2);
strcat(s1, s2);
getnext(s1);
int ans = nex[strlen(s1)];
while (ans > s1len || ans > s2len)
{
ans = nex[ans];
}
if (ans == 0 || ans == -1)
{
printf("0\n");
}
else
{
s1[ans] = 0;
printf("%s %d\n", s1, ans);
}
}
return 0;
}
扩展kmp的ac代码:
扫描二维码关注公众号,回复:
3927710 查看本文章
#include <stdio.h>
#include <iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn = 100010; //字符串长度最大值
int nex[maxn], ex[maxn]; //ex数组即为extend数组
//预处理计算next数组
void GETNEXT(char *str)
{
int i = 0, j, po, len = strlen(str);
nex[0] = len;//初始化next[0]
while (str[i] == str[i + 1] && i + 1 < len)//计算next[1]
i++;
nex[1] = i;
po = 1;//初始化po的位置
for (i = 2; i < len; i++)
{
if (nex[i - po] + i < nex[po] + po)//第一种情况,可以直接得到next[i]的值
nex[i] = nex[i - po];
else//第二种情况,要继续匹配才能得到next[i]的值
{
j = nex[po] + po - i;
if (j < 0)j = 0;//如果i>po+next[po],则要从头开始匹配
while (i + j < len&&str[j] == str[j + i])//计算next[i]
j++;
nex[i] = j;
po = i;//更新po的位置
}
}
}
//计算extend数组
void EXKMP(char *s1, char *s2)
{
int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
GETNEXT(s2);//计算子串的next数组
while (s1[i] == s2[i] && i < l2&&i < len)//计算ex[0]
i++;
ex[0] = i;
po = 0;//初始化po的位置
for (i = 1; i < len; i++)
{
if (nex[i - po] + i < ex[po] + po)//第一种情况,直接可以得到ex[i]的值
ex[i] = nex[i - po];
else//第二种情况,要继续匹配才能得到ex[i]的值
{
j = ex[po] + po - i;
if (j < 0)j = 0;//如果i>ex[po]+po则要从头开始匹配
while (i + j < len&&j < l2&&s1[j + i] == s2[j])//计算ex[i]
j++;
ex[i] = j;
po = i;//更新po的位置
}
}
}
int main()
{
char s1[maxn], s2[maxn];
while (~scanf("%s%s", s1, s2))
{
EXKMP(s2, s1);
int len = strlen(s2);
int maxx= 0;
int maxx_i = 0;
int flag = 0;
for (int i = 0; i < len; i++)
{
if (ex[i] > maxx && ex[i] + i == len)//ex[i]代表s2[i...len-1]和s1 最长的公共前缀的长度
{
maxx = ex[i];
maxx_i = i;
}
}
if (maxx)
{
printf("%s %d\n", s2 + maxx_i, maxx);
}
else
puts("0");
}
return 0;
}