字符串哈希

字符串哈希用来解决字符串匹配问题。设文本串的长度为\(n\),模式串的长度为\(m\),通过滚动哈希优化可以在\(O(n+m)\)的时间复杂度内完成匹配
选取两个互素常数\(b\)\(m\)\(b\)可以选择\(131,13331\)等,可以降低哈希冲突的概率,\(m\)通常选择\(2^{64}\),通过自然溢出省去取模运算

哈希函数:\(H(S[c+1,\cdots,c+k])=(H(S[c,\cdots,c+k-1])*b+S[c+k]-S[c]*b^k)\ mod\ m\)
这样可以不断通过右移一位计算子串的哈希值,将所有位置的哈希值与模式串的哈希值比较,完成匹配

也可以预处理字符串所有前缀的哈希值和基数的幂次,设前缀的哈希值数组为\(hash[maxn]\),基数的幂次数组为\(pre[maxn]\),则有:\(H(S[c+1,\cdots,c+k])=hash[c+k]-hash[c]*pre[k]\)
模板:字符串哈希,预处理前缀以及幂次

const int maxn=100010;
const ULL base=131;
char s[maxn];
ULL pre[maxn],hash[maxn];

void init(){
    pre[0]=1;
    for(ULL i=1;i<=100005;i++) pre[i]=pre[i-1]*base;
}

void Hash(int n){
    for(int i=1;i<=n;i++){
        hash[i]=hash[i-1]*base+s2[i]-'a'+1;
    }
}

ULL getHash(ULL s[],int l,int r){
    return s[r]-s[l-1]*pre[r-l+1];
}

相关题目:hdu4080 Stammering Aliens
     二分+字符串哈希

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define ull unsigned long long
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;

const int maxn=40010;
const ull b=13331;
int m,n;
ull f[maxn],p[maxn];
char s[maxn];
map<ull,int> mp;

bool check(int x){
    mp.clear();
    ull res;
    for(int i=1;i+x-1<=n;i++){
        res=f[i+x-1]-f[i-1]*p[x];
        mp[res]++;
        if(mp[res]>=m) return true;
    }
    return false;
}

int get(int x){
    mp.clear();
    int pos=-1;
    ull res;
    for(int i=1;i+x-1<=n;i++){
        res=f[i+x-1]-f[i-1]*p[x];
        mp[res]++;
        if(mp[res]>=m) pos=i;
    }
    return pos-1;
}

int main(){
    while(scanf("%d",&m)!=EOF && m){
        scanf("%s",s+1);
        n=strlen(s+1);
        f[0]=0;
        p[0]=1;
        for(int i=1;i<=n;i++){
            f[i]=f[i-1]*b+s[i];
            p[i]=p[i-1]*b;
        }
        int l=0,r=n;
        while(r>l){
            int mid=(l+r+1)>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        if(l==0) printf("none\n");
        else printf("%d %d\n",l,get(l));
    }
    return 0;
}
posted @ 2020-08-08 17:47  fxq1304  阅读(97)  评论(0)    收藏  举报