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
  • 相关阅读:
    oracle常用的sql语句
    Tomcat内存调优
    基于Linux服务器的Oracle自动备份以及定时清除
    Windows 中Oracle数据库定时备份与清除
    CentOS 7 root密码修改
    weblogic忘记用户密码
    weblogic修改密码
    通过python自动获取小说并下载
    Linux修改本机名称
    CentOS无法正常启动
  • 原文地址:https://www.cnblogs.com/de-compass/p/11842714.html
Copyright © 2011-2022 走看看