字符串Hash學習筆記

[toc]ios

# 如下內容做廢,太多錯誤了,等我有時間重寫算法

 

說一下什麼是Hash,說白了就是把一大坨字符用一些神奇的數來表示,能夠說是把字符加密了.函數

簡單一點就是一個像函數同樣的東西,你放進去一個值,它給你輸出來一個值。輸出的值就是Hash值。通常Hash值會比原來的值更好儲存(更小)或比較。加密

字符串hash的靈魂就是儘可能讓不一樣的字符串對應惟一的hsah的值 .而要實現這一效果就要選對方法不然就咕咕咕了spa

舉個栗子:code

若是咱們的加密方法是把字符的ascal加起來,那就咕咕咕了.xml

好比:blog

ababa字符串

babaaget

加起來是同樣的,咕咕咕....

 

因此應該怎麼hash?

用一種名爲「BKDR Hash」的字符串Hash算法:

它的主要思路是選取恰當的進制,能夠把字符串中的字符當作一個大數字中的每一位數字,不過比較字符串和比較大數字的複雜度並無什麼區別(高精數的比較也是O(n)O(n)的),但只要把它對一個數取模,而後認爲取模後的結果相等原數就相等,那麼就能夠在必定的錯誤率的基礎上O(1)O(1)進行判斷了。

那麼咱們選擇什麼進制比較好?

首先不要把任意字符對應到數字0,好比假如把a對應到數字0,那麼將不能只從Hash結果上區分ab和b(雖然能夠額外判斷字符串長度,但不把任意字符對應到數字0更加省事且沒有任何反作用),通常而言,把a-z對應到數字1-26比較合適。

關於進制的選擇實際上很是自由,大於全部字符對應的數字的最大值,不要含有模數的質因子(那還模什麼),好比一個字符集是a到z的題目,選擇2七、23三、19260817都是能夠的。

模數的選擇(儘可能仍是要選擇質數):

絕大多數狀況下,不要選擇一個109109級別的數,由於這樣隨機數據都會有Hash衝突,根據生日悖論,隨便找上109−−−√109個串就有大機率出現至少一對Hash 值相等的串

最穩妥的辦法是選擇兩個109109級別的質數,只有模這兩個數都相等才判斷相等,但常數略大,代碼相對難寫,目前暫時沒有辦法卡掉這種寫法(除了卡時間讓它超時)

若是能背過或在考場上找出一個10181018級別的質數(Miller-Rabin),也相對靠譜,主要用於前一種擔憂會超時,後一種擔憂被卡。

偷懶的寫法就是直接使用unsigned long long,不手動進行取模,它溢出時會自動對264

 

送上一道模板題:

P3370 【模板】字符串哈希

題目描述

如題,給定N個字符串(第i個字符串長度爲Mi,字符串內包含數字、大小寫字母,大小寫敏感),請求出N個字符串中共有多少個不一樣的字符串。

輸入輸出格式

輸入格式:

 

第一行包含一個整數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

 

代碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
#define ll long long int
#define mod 1000000007
using namespace std;
const long long int  maxn=99999999999999;
const int minn=-999999999;
long long  base=131;
long long  a[15010];
char s[15010];
int n,ans=1;
long long hash(char s[]) {
    int len=strlen(s);
    long long  ans=0;
    for (int i=0; i<len; i++)
        ans=ans*base+(long long )s[i];
    return ans%maxn;
}
int main() {
    scanf("%d",&n);
    for (int i=1; i<=n; i++) {
        scanf("%s",s);
        a[i]=hash(s);
    }
    sort(a+1,a+n+1);
    for (int i=2; i<=n; i++)
        if (a[i]!=a[i-1])
            ans++;
    printf("%d\n",ans);
}

 

送上取膜數對答案的影響:

 .

 改了一下mod爲0x3f3f3f就

 

 

因此hsah最的最後一步:燒香拜佛保AC!

相關文章
相關標籤/搜索