第一题,很简单的板子题,只需要把char 改成int类型就好了
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000005;
int Next[N];
int S[N], T[N];
int slen, tlen;//注意每次一定要计算长度
void getNext()
{
int j, k;
j = 0; k = -1; Next[0] = -1;
while(j < tlen)
if(k == -1 || T[j] == T[k])
Next[++j] = ++k;
else
k = Next[k];
}
int KMP_Index()
{
int i = 0, j = 0;
getNext();
while(i < slen && j < tlen)
{
if(j == -1 || S[i] == T[j])
{
i++; j++;
}
else
j = Next[j];
}
if(j == tlen)
return i - tlen+1;
else
return -1;
}
int main()
{
int TT;
int i, cc;
scanf("%d",&TT);
while(TT--)
{
int i,j,m,n;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d",&S[i]);
}
for(j=0;j<m;j++)
{
scanf("%d",&T[j]);
}
slen = n;
tlen = m;
printf("%d\n",KMP_Index());
}
return 0;
}
第二题,仍然为板子题,求母串里有几个子串
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000005;
int Next[N];
char S[N], T[N];
int slen, tlen;//注意每次一定要计算长度
void getNext()
{
int j, i,k;
j = 0; k = -1; Next[0] = -1;
while(j < tlen)
if(k == -1 || T[j] == T[k])
{
Next[++j] = ++k;
}
else
{
k = Next[k];
}
}
int KMP_Count()
{
int ans = 0;
int i, j = 0;
if(slen == 1 && tlen == 1)
{
if(S[0] == T[0])
return 1;
else
return 0;
}
getNext();
for(i = 0; i < slen; i++)
{
while(j>=0 && S[i] != T[j])
j = Next[j];
if(j==-1||S[i] == T[j])
j++;
if(j == tlen)
{
ans++;
j = Next[j];
}
}
return ans;
}
int main()
{
int TT;
int i, cc;
scanf("%d",&TT);
while(TT--)
{
scanf("%s",T);
scanf("%s",S);
slen = strlen(S);
tlen = strlen(T);
printf("%d\n",KMP_Count());
}
return 0;
}
第三题,仍然板子,但是要注意,这里不能重复使用,所以当j==tlen时,j不再等于
Next[j]而是直接等于0;
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000005;
int Next[N];
char S[N], T[N];
int slen, tlen;//注意每次一定要计算长度
void getNext()
{
int j, i,k;
j = 0; k = -1; Next[0] = -1;
while(j < tlen)
if(k == -1 || T[j] == T[k])
{
Next[++j] = ++k;
}
else
{
k = Next[k];
}
}
int KMP_Count()
{
int ans = 0;
int i, j = 0;
if(slen == 1 && tlen == 1)
{
if(S[0] == T[0])
return 1;
else
return 0;
}
getNext();
for(i = 0; i < slen; i++)
{
while(j>=0 && S[i] != T[j])
j = Next[j];
if(j==-1||S[i] == T[j])
j++;
if(j == tlen)
{
ans++;
j = 0;
}
}
return ans;
}
int main()
{
int TT;
int i, cc;
while(scanf("%s",S)!=EOF)
{
if(S[0]=='#')
break;
scanf("%s",T);
slen = strlen(S);
tlen = strlen(T);
printf("%d\n",KMP_Count());
}
return 0;
}
第4题,kmp中next数组的应用,主要是找循环节的大小,最少在后面加几个字符才能使其成为循环
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000002;
int Next[N];
char a[N];
int slen, tlen;
void getNext()
{
int j, k;
j = 0; k = -1; Next[0] = -1;
while(j < tlen)
if(k == -1 || a[j] == a[k])
Next[++j] = ++k;
else
k = Next[k];
}
int main()
{
int i,j,m,n;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",a);
tlen=strlen(a);
getNext();
j=tlen-Next[tlen];
if(tlen%j==0&&j!=tlen)//注意j==tlen的情况,即他本身就是一个循环节
printf("0\n");
else
{
printf("%d\n",j-Next[tlen]%j);//注意%j因为像abcabcab中next最后一个为5
}
}
return 0;
}