• [模板]字符串哈希的简易做法


    题目描述

    如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串。

    友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:)

    输入输出格式

    输入格式:

    第一行包含一个整数N,为字符串的个数。

    接下来N行每行包含一个字符串,为所提供的字符串。

    输出格式:

    输出包含一行,包含一个整数,为不同的字符串个数。

    输入输出样例

    输入样例#1:
    5
    abc
    aaaa
    abc
    abcc
    12345
    输出样例#1:
    4

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,Mi≈6,Mmax<=15;

    对于70%的数据:N<=1000,Mi≈100,Mmax<=150

    对于100%的数据:N<=10000,Mi≈1000,Mmax<=1500

    样例说明:

    样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。

    Tip: 感兴趣的话,你们可以先看一看以下三题:

    BZOJ3097:http://www.lydsy.com/JudgeOnline/problem.php?id=3097

    BZOJ3098:http://www.lydsy.com/JudgeOnline/problem.php?id=3098

    BZOJ3099:http://www.lydsy.com/JudgeOnline/problem.php?id=3099

    如果你仔细研究过了(或者至少仔细看过AC人数的话),我想你一定会明白字符串哈希的正确姿势的^_^

    Solution:

    首先你得会写链式前向星(即链表/邻接表,常用于存储图)。将一个字符串看成255进制数,然后把它转成十进制数,并找一个大质数对该十进制数取模。这里你也可以使用秦九韶算法(很简单,可以百度,名字高端了一点;如果不会你怎么转的k到10进制就怎么转233),就能获得这个字符串的哈希值了。

    然后如何判重?两个字符串的哈希值相同就证明这两个字符串相同——原本应该是这样的。但由于取模,确实可能出现两个字符串hash值出现重复的情况。这时我们就需要套个邻接表,给每个哈希值下的字符串都判断一遍。如果没有字符串相同,再往这个哈希值下插入这个字符串,并计数加一。事实证明,哈希值冲突的情况不多,如果链式前向星写得熟那更是万无一失。Luogu评测耗时为500ms左右,比很多评测记录还是快很多。如果只是一般的Hash,我觉得用这个基本上就够了的说....=、=想办法把要记录的状态转成k进制数,再转成10进制数对大质数取模,然后套进邻接表来判重。代码复杂度不高,而且效率也不差。

    怎么把字符串在邻接表里套进同一哈希值?嗯....你把它看作图论里的插边。我觉得这两种东西差不多。

    所谓的大质数....嗯嗯,我不管那么多的,我直接1000013就做了。如果想要靠谱一点的大质数....百度哇。

    下面是代码。

    #include<bits/stdc++.h>
    using namespace std;
    const int MOD=1e6+13,N=10010;
    
    int h[MOD],nexp[N],p=1;
    string s[N];//链式前向星 
    
    int getHash(string x){
        int plus=255,ret=x[0],len=x.size();
        for(int i=1;i<len;i++){
            ret=(ret*plus)%MOD;
            ret+=x[i];
        }
        return ret%MOD;
    }//获取字符串的哈希值 
    bool insHash(string x){
        int c=getHash(x);
        for(int u=h[c];u;u=nexp[u]){
            if(s[u]==x)return 0;//若发现重复则返回0 
        }
        nexp[p]=h[c],h[c]=p,s[p]=x,p++;
        return 1;//否则插入 
    }
    
    
    int main(){
        std::ios::sync_with_stdio(false); //相关内容可以百度搜索,可以加快cin效率 
        int n;
        cin>>n;
        string a;
        int ans=0;
        for(int i=0;i<n;i++){
            cin>>a;
            if(insHash(a))ans++;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    迭代器、生成器、装饰器(转)
    Python小数据池
    接阿里云oss有感
    VSCode快捷键
    前端跨域调请求 nginx反向代理
    Git生成密钥
    【westorm系列之二】配置格式化
    钉钉安卓端无法渲染数据
    express 写接口
    js正则匹配身份证号 有坑
  • 原文地址:https://www.cnblogs.com/acxblog/p/7253477.html
Copyright © 2020-2023  润新知