【练习】POJ - 3461 Oulipo(KMP/字符串Hash)

题意

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;
}
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/pengwill97/article/details/80991544
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞