这几天写了几道题
P3375 【模板】KMP - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P3370 【模板】字符串哈希 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P4391 [BOI2009] Radio Transmission 无线传输 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
第一个是kmp的模板题,直接套板子就行,但是这里有一个要注意的点就是,这个题中模式串里面可能有多个字串,就会有多个答案,还要输出一下next数组
下面附上代码:
#include<stdio.h>
#include<string.h>
#define N 1000010
char A[N],B[N];
int p[N];
int main()
{
scanf("%s%s",A+1,B+1);
int i,j=0;
p[1]=0;
int n=strlen(A+1),m=strlen(B+1);
for(int i=1;i<m;i++)//构建next数组(这里是p数组)
{
while(j&&B[j+1]!=B[i+1])//如果不是第一个字符就不匹配,j就回退
j=p[j];
if(B[i+1]==B[j+1])//匹配成功j就++,循环结束i会自加
j++;
p[i+1]=j;//给next数组赋值
}
//kmp算法
j=0;
for(int i=0;i<n;i++)
{
while(j&&B[j+1]!=A[i+1])
j=p[j];
if(B[j+1]==A[i+1])
j++;
if(j==m)//匹配成功
{
printf("%d\n",i-strlen(B+1)+2);
j=p[j];//下次继续匹配
}
}
for(int i=1;i<=m;i++)//输出next数组
printf("%d ",p[i]);
return 0;
}
第二个题目时hash的模板题,我理解的哈希就是将一个字符串(大部分时用于字符串)用一个哈希值表示,这个哈希值来表示,凭此哈希值来区分字符串的不同,当然,不同的字符串的哈希值可能会相同(也就是哈希冲突),我们会尽量避免这种哈希冲突
下面附上代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define ull unsigned long long int
#define N 10010
ull base=131;//最好是一个素数
ull a[N];//存放字符串的哈希值
char s[N];
ull hash(char s[])//返回一个字符串的哈希值res
{
int len=strlen(s);
ull res=0;
for(int i=0;i<len;i++)
res=(res*base+(ull)s[i])%(ull)pow(2,32);
return res;
}
void qsort(int l,int r)//快排函数
{
ull temp=a[(l+r)/2];
int i=l,j=r;
while(1)
{
if(i>=j)
break;
while(a[j]>temp)
j--;
while(a[i]<temp)
i++;
if(i<=j)
{
ull temp1=a[i];
a[i]=a[j];
a[j]=temp1;
i++;
j--;
}
}
if(j>l)
qsort(l,j);
if(i<r)
qsort(i,r);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
a[i]=hash(s);
}
qsort(1,n);
// for(int i=1;i<=n;i++)
// printf("%d ",a[i]);
// printf("\n");
int sum=1;
for(int i=1;i<n;i++)
if(a[i]!=a[i+1])
sum++;
printf("%d",sum);
return 0;
}
第三题时一个对kmp算法中的next数组理解有很大帮助的一个题目,写完后你会发现对next数组的理解又深一点,利用next数组来求出最短重复序列的长度,next[x]=0,next[x+1]=1,next[x+2]=2,....其中x就是最短重复序列的值,这个规律应该很容易就能理解,根据此规律就能求出最短重复序列的长度x=n-next[n-1],n为串的长度(next[i]记录的就是i前面的前缀和后缀的最长重复长度)
下面附上代码:
#include<stdio.h>
#define N 1000010
int l;
char s1[N];
int next[N];
int main()
{
scanf("%d%s",&l,s1);
next[0]=0;
int j=0;
for(int i=1;i<l;i++)
{
while(j&&s1[i]!=s1[j])
j=next[j-1];
if(s1[i]==s1[j])
j++;
next[i]=j;
}
// for(int i=0;i<l;i++)
// printf("%d ",next[i]);
printf("%d",l-next[l-1]);//可以自己推导试试
return 0;
}