题意
PJ的女朋友是一个书法家,喜欢写一些好看的英文书法。有一天PJ拿到了她写的纸条,暗示要送给他生日礼物。PJ想知道自己想要的礼物是不是就是她送的,于是想看看自己想要的在纸条中出现了多少次。
题解
KMP
注意如果匹配之后K值的选择。由于匹配的串之间是可以有重叠的部分的,所以这里发生匹配之后要当发生适配对K进行回退,这样就能保证在主串指针不回退的情况下完成匹配。不妨以样例为例:
str | 最长前缀=最长后缀的串 | next n e x t |
---|---|---|
A A | null n u l l | -1 |
AZ A Z | null n u l l | -1 |
AZA A Z A | A A | 0 |
从上表可见, AZA A Z A 的 next n e x t 值为0.
所以当模式串与文本串的第一个 AZA A Z A 发生匹配的时候,接下来应该看这个位置是否和模式串的第1个字符是否相同,如此可保证在主指针不回退的情况下继续进行。
Hash
如果用Hash就比较水,依次枚举子串,看Hash值是否相同即可。
代码
KMP
#include<cstdio>
#include<cstring>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
char text[nmax],str[nmax];
int t,lentext,lenstr,nxt[nmax];
inline void getnxt(){
nxt[0] = -1; int k = -1;
for(int i = 1;i<=lenstr-1;++i){
while(k>-1 && str[k+1] != str[i]) k = nxt[k];
if(str[k+1] == str[i]) k++;
nxt[i] = k;
}
}
inline int KMP(){
lentext = strlen(text),lenstr = strlen(str);
getnxt();
int k = -1,ans = 0;
for(int i = 0;i<=lentext-1;++i){
while(k>-1 && str[k+1] != text[i]) k = nxt[k];
if(str[k+1] == text[i]) k++;
if(k == lenstr-1){
// i = i - lenstr + 1; 这样会超时
k = nxt[k];
ans++;
}
}
return ans;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%s %s",str,text);
printf("%d\n",KMP());
}
return 0;
}
Hash
#include<cstdio>
#include<cstring>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int t,lentext,lenstr;
char text[nmax],str[nmax];
ull hashtext[nmax],hashstr[nmax],pp[nmax];
inline void init(){
pp[1] = p; for(int i = 2;i<=1000000;++i) pp[i] = pp[i-1] * p;
}
inline void gethash(){
hashtext[1] = text[1], hashstr[1] = str[1];
for(int i = 2;i<=lentext;++i) hashtext[i] = hashtext[i-1] * p + text[i];
for(int i = 2;i<=lenstr;++i) hashstr[i] = hashstr[i-1] * p + str[i];
}
inline ull subhash(int l, int r){
return hashtext[r] - hashtext[l-1] * pp[r-l+1];
}
int main(){
init();
scanf("%d",&t);
while(t--){
scanf("%s %s",str+1,text+1);
lentext = strlen(text+1), lenstr = strlen(str+1);
gethash();
int l = 1,ans=0;
while(true){
int r = l + lenstr -1;
if(subhash(l,r) == hashstr[lenstr]) ans++;
l++;
if(l + lenstr -1 > lentext) break;
}
printf("%d\n",ans);
}
return 0;
}