挑了一些典型的题目写一下
题意:
给出俩个字符串a和b,问你字符串a在字符串b的总出现次数是多少,即aaa在aaaa中出现了2次
题解:
kmp算法,在函数中当j==l2的时候令j=next[j]
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxx = 10005;
int next1[maxx],cnt = 0;
char s1[maxx*100],s2[maxx];
void getnext(char s[]){
int j=0,k=-1,len = strlen(s);
next1[0] = -1;
while(j < len){
if(k == -1 || s[j] == s[k]){
next1[++j] = ++k;
}
else
k = next1[k];
}
}
int kmp(char s1[],char s2[])
{
getnext(s2);
int i=0,j=0;
int l1 = strlen(s1),l2 = strlen(s2);
while(i < l1){
if(j == -1 || s1[i] == s2[j])
i++,j++;
else
j = next1[j];
if(j == l2){
cnt++;
j = next1[j];
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cnt = 0;
scanf("%s",s2);
scanf("%s",s1);
kmp(s1,s2);
printf("%d\n",cnt);
}
return 0;
}
题意:
和上一题题意差不多,但是是求不重复覆盖的子字符串的出现次数,比如aa在aaaaaa中出现了3次
题解:
在kmp函数中,当j==l2的时候j=0即可
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxx = 1005;
int next1[maxx],cnt = 0;
char s1[maxx],s2[maxx];
void getnext(char s[]){
int j=0,k=-1,len = strlen(s);
next1[0] = -1;
while(j < len){
if(k == -1 || s[j] == s[k]){
next1[++j] = ++k;
}
else
k = next1[k];
}
}
void kmp(char s1[],char s2[])
{
getnext(s2);
int i=0,j=0;
int l1 = strlen(s1),l2 = strlen(s2);
while(i < l1){
if(j == -1 || s1[i] == s2[j])
i++,j++;
else
j = next1[j];
if(j == l2){
cnt++;
j = 0;
}
}
}
int main()
{
while(~scanf("%s %s",s1,s2))
{
cnt = 0;
if(strcmp(s1,"#") == 0){
break;
}
kmp(s1,s2);
printf("%d\n",cnt);
}
return 0;
}
题意:
给出一个字符串,要求将其补全成一个可以循环的字符串,输出最少添加的字符的个数,如果本身就是一个循环的字符串,输出0
题解:
用kmp求出来next数组,那么len - next[len] 就代表循环字符串的长度
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxx = 100005;
int next1[maxx],cnt = 0;
char s1[maxx];
void getnext(char s[]){
int j=0,k=-1,len = strlen(s);
next1[0] = -1;
while(j < len){
if(k == -1 || s[j] == s[k]){
next1[++j] = ++k;
}
else
k = next1[k];
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s1);
getnext(s1);
int len = strlen(s1);
if(!next1[len]){
printf("%d\n",len);
continue ;
}
int k = len - next1[len];
if(len % k == 0)
printf("0\n");
else
printf("%d\n",k-len%k);
}
return 0;
}
题意:
给出一个字符串,输出这个字符串最多可以分成几个相同的子字符串,例如ababab可以拆成3个ab,输出3
题解:
kmp求next数组,那么i - next[len]是循环字符串的长度,如果len%(i-next[len]) == 0,说明可以拆成至少2个子字符串,输出len/(i-next[len]);否则输出1.
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxx = 1000005;
int next1[maxx],cnt = 0;
char s1[maxx];
void getnext(char s[]){
int j=0,k=-1,len = strlen(s);
next1[0] = -1;
while(j < len){
if(k == -1 || s[j] == s[k]){
next1[++j] = ++k;
}
else
k = next1[k];
}
}
int main()
{
while(~scanf("%s",s1))
{
if(strcmp(s1,".") == 0)
break;
int len = strlen(s1);
getnext(s1);
int k = len - next1[len];//循环节的长度!!!
if(len%k == 0){
printf("%d\n",len/k);
continue ;
}
printf("1\n");
}
return 0;
}
题意:
这算是和上一题的问题差不多,只不过多了个循环
题解:
循环求i-next[i]
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxx = 1000005;
int next1[maxx],cnt = 0;
char s1[maxx];
void getnext(char s[]){
int j=0,k=-1,len = strlen(s);
next1[0] = -1;
while(j < len){
if(k == -1 || s[j] == s[k]){
next1[++j] = ++k;
}
else
k = next1[k];
}
}
int main()
{
int len,t = 0;
while(~scanf("%d",&len))
{
if(len == 0)
break;
scanf("%s",s1);
getnext(s1);
printf("Test case #%d\n",++t);
for(int i=2;i<=len;i++)
{
int len2 = i - next1[i];//存在的循环节的长度!!!
if(i%len2 == 0 && i != len2){
printf("%d %d\n",i,i/len2);
}
}
printf("\n");
}
return 0;
}
题意:
这算是这一套最好的一道题,彻底弄明白next数组,输入一个字符串,输出字符串的前缀,后缀长度相同且字符完全匹配的长度
题解:
递归,先kmp求出next数组,从next[len]往前递归,
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxx = 400005;
int next1[maxx],ans[maxx],cnt = 0;
char s1[maxx];
void getnext(char s[]){
int i=0,j=-1,len = strlen(s);
next1[0] = -1;
while(i < len){
if(j == -1 || s[i] == s[j]){
next1[++i] = ++j;
}
else
j = next1[j];
}
}
int main()
{
while(~scanf("%s",s1))
{
int sum = 0;
int len = strlen(s1);
getnext(s1);
int k = next1[len];
while(k > 0){
ans[++sum] = k;
k = next1[k];
}
for(int i=sum;i>=1;i--){
printf("%d ",ans[i]);
}
printf("%d\n",len);
}
return 0;
}