题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1841
表示这个题目做起来还是有点意思的
首先分析一下解这个题目要考虑的两种情况
1、一个串在另外一个串中,那么结果就是两个串中长度长的哪一个
2、一个串的头部是另外一个串的尾部,这里分两种情况(每个串都有一头一尾嘛)
明白上面两点之后开始用KMP解题
首先直观的普通解法是两个串相互前后拼接一次,然后求出next值,最后一个位置的next值,也就是next[len1+len2]
就是两个串最长头尾公共部分(由于后面要讨论串包含关系,所以这里不考虑next[len1+len2]大于位置在前面那个串
的长度
这个完成之后就是判断有没有包含关系了,其实这个也简单,就是短串在长串里面求匹配嘛,对短串求一次next
然后在长串里面匹配一下,看看能否找到匹配就OK了嘛,这样做完全可以,而且复杂度也不高,能通过这个题目
但是这里仅仅要找短串是否在长串里面出现过,如果直接重新求next值,再求匹配,那么先前求的两个串拼接起
来的串的next值就木有用上,那么怎么利用原有的两个拼接串来判断一个串在另外一个串中是否有匹配呢,其实
很简单了,就是判断next[len1*2](len1<len2)之后的next值,如果有next[i]>=len1的那么说明在后面的串部分的i
位置存在一个长度大于等于len1的在i前面的部分和整个串的前缀部分相等,好了,找到了!
其实这样做只是对KMP有一定理解,其实这个题目还是很卡常数的!
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define maxn 1000010
#define MIN(a,b) (a<b?a:b)
#define MAX(a,b) (a>b?a:b)
char str[maxn],rec[maxn],temp[maxn*2];
int next[maxn*2];
int get_next()
{
int i=0,j=-1;
next[0]=-1;
while(temp[i])
{
if(j==-1 || temp[i]==temp[j])
{
i++,j++;
next[i]=j;
}
else
j=next[j];
}
return 0;
}
bool find_ans(int len1,int len2,int len)
{
for(int i=len1*2;i<=len;i++)
if(next[i]>=len1)
return 1;
return 0;
}
int main()
{
int t;
int len1,len2,len,ans;
scanf("%d",&t);
while(t--)
{
scanf("%s%s",str,rec);
len1=strlen(str);
len2=strlen(rec);
len=len1+len2;
ans=len;
strcpy(temp,str);
strcpy(temp+len1,rec);
get_next();
ans=len-next[len];// 这里不需要做特殊判断,如果两个串有包含关系后面会检测出来
if(len1 <=len2)
{
if(find_ans(len1,len2,len))
{
printf("%d\n",MAX(len1,len2));
continue;
}
}
strcpy(temp,rec);
strcpy(temp+len2,str);
get_next();
if(len2<=len1)
{
if(find_ans(len2,len1,len))
{
printf("%d\n",MAX(len1,len2));
continue;
}
}
ans=MIN(ans,len-next[len]);
printf("%d\n",ans);
}
return 0;
}