zoukankan      html  css  js  c++  java
  • 【转载】字符串Hash & 【题解】好文章

    以下内容来源https://blog.csdn.net/Coldfresh/article/details/79476915, 作者Coldfresh

    字符串hash是指将一个字符串s映射为一个,使得该整数可以尽可能唯一的代表也就是唯一标识。换言之,如果两个字符的hash值相同那么我们可以认为两者相同。

    这里使用的hash策略,便是把一个字符串的每一位赋予权值
    假设都是大写的英文字母。
    我们设
    H[i]代表前i个hash值

    那么
    H[i]=H[i−1]∗p+val[i]

    这里因为是大写英文字母,只有26 中不同的表示,所以这里可以设p为26。(实际上就是把26进制数用10进制数表示)
    接下的问题是如果字符串的位数很长,那么很可能所产生的hash值会超过技术表示的范围(以int和long类型为例)。
    所以我们可以设置一个数mod,即去余
    H[i]=(H[i−1]∗p+val[i])%mod
    那么这样可以解决数字太大的问题,但是会造成的另一个问题是产生碰撞,即不同的字符串的hash值可能会相同。
    根据相关资料,如果我们把p设置为一个10^7(如10000019)大小,把mod设为一个10^9(如1000000009)大小的数,那么发生碰撞的概率就非常低。
    后来我问斌爷,斌爷说把p设为233就够啦,基本上碰撞的概率极小233。

    一个延伸问题:如果我得到了一个字符串的hash值,那么怎么得到其中任意一个子串的hash?
    首先易知:
    H[i...j]=val[i]∗p^(j−i)+val[i+1]∗p^(j−i−1)+val[i+2]∗p^(j−i−2)+...+val[j]∗p^0

    显然:
    H[j]=H[i−1]∗p^(j−i+1)+H[i...j]

    所以:
    H[i...j]=(H[j]−H[i−1]∗p^(j−i+1))

    这个时候去模:
    H[i...j]=((H[j]−H[i−1]∗p^(j−i+1))%mod+mod)%mod

    完毕。


    以上为转载内容。

    如果仍怕冲突,可以开不同种子的Hash表共同判断。

    const int maxn = 10005;
    int n;
    char s[maxn];
    struct Hash {
        int p,P,hash1[maxn],hash2[maxn];//hash1[i]是上文的H[i],hash2[i]是上文的p^i
        void init(int p1,int P1) {
            p=p1,P=P1;
            hash2[0]=1;
            for(int i=1; i<=n; i++) {
                hash1[i]=(1LL*hash1[i-1]*p+(s[i]-'a'+1))%P;
                hash2[i]=1LL*hash2[i-1]*p%P;
            }
        }
        int getha(int L,int R) {
            return (hash1[R]-1LL*hash1[L-1]*hash2[R-L+1]%P+P)%P;
        }
    };

    例题:

    好文章:

    Description

      nodgd写了一篇文章,自认为这是一篇好文章。nodgd的文章由n个小文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,决定给自己的文章进行评分。nodgd 首先确定了一个整数m,然后统计出文有多少个不相同的长度为m的子串,这个数量就是文章的评分。 

      然而,nodgd懒得老老实实计算这个评分了,就把任务丢给了你。

    Input

      第一行包含两个整数n,m,表示文章的长度和需要统计的子串长度。   第二行包含一个长度为n的只包含小写字母的字符串。

    Output

      输出一行一个整数,表示文章的评分。

    Sample Input 1 

    【样例1】
    5 3
    aaaab
    
    【样例2】
    9 3
    abcabacba

    Sample Output 1

    【样例1】
    2
    【样例2】 7

    Hint

    对于 30%的数据,1 ≤ m ≤ n ≤ 200;
    对于 50%的数据,1 ≤ m ≤ n ≤ 2000;
    对于另外20%的数据,1 ≤ m ≤ 50 ≤ n ≤ 200000;
    对于 100%的数据,1 ≤ m ≤ n ≤ 200000;

    双哈希案例,出题人卡数据:
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=5e5+5, mod1=1e9+7, mod2=1e9+9;
    int n,m;
    char s[maxn];
    //哈希表 
    struct Hash {
        int p,P,hash1[maxn],hash2[maxn];
        void init(int p1,int P1) {
            p=p1,P=P1;
            hash2[0]=1;
            for(int i=1; i<=n; i++) {
                hash1[i]=(1LL*hash1[i-1]*p+(s[i]-'a'+1))%P;
                hash2[i]=1LL*hash2[i-1]*p%P;
            }
        }
        int getha(int L,int R) {
            return (hash1[R]-1LL*hash1[L-1]*hash2[R-L+1]%P+P)%P;
        }
    } Ha,Hb;
    struct Charactor {
        int h1,h2;
        bool operator<(const Charactor& h)const {
            return h1==h.h1?h2<h.h2:h1<h.h1;
        }
    } H[maxn];
    int main() {
        int i,j,ans=1;
        scanf("%d%d", &n, &m);
        scanf("%s", s+1);
        Ha.init(47, mod1);//不同种子 
        Hb.init(91, mod2);
        for(i=1; i+m-1<=n; i++) {
            H[i].h1=Ha.getha(i,i+m-1);
            H[i].h2=Hb.getha(i,i+m-1);
        }
        sort(H+1,H+1+n-m+1);
        for(i=2; i+m-1<=n; i++)
            ans+=(H[i].h1!=H[i-1].h1||H[i].h2!=H[i-1].h2);//两个哈希中有一个不等即可 
        cout<<ans;
    }
    View Code
  • 相关阅读:
    【转】win8.1下安装ubuntu
    Codeforces 1025G Company Acquisitions (概率期望)
    Codeforces 997D Cycles in Product (点分治、DP计数)
    Codeforces 997E Good Subsegments (线段树)
    Codeforces 1188E Problem from Red Panda (计数)
    Codeforces 1284E New Year and Castle Building (计算几何)
    Codeforces 1322D Reality Show (DP)
    AtCoder AGC043C Giant Graph (图论、SG函数、FWT)
    Codeforces 1305F Kuroni and the Punishment (随机化)
    AtCoder AGC022E Median Replace (字符串、自动机、贪心、计数)
  • 原文地址:https://www.cnblogs.com/de-compass/p/11842714.html
Copyright © 2011-2022 走看看