1. 程式人生 > >[模板]字符串哈希的簡易做法

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

online als 左右 描述 return 質數 取字符 這樣的 class

題目描述

如題,給定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;
}

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