hash基本原理:
hash就是乙個像函式一樣的東西,你放進去乙個值,它給你輸出來乙個值。輸出的值就是hash值。一般hash值會比原來的值更好儲存(更小)或比較。
那字串hash就非常好理解了。就是把字串轉換成乙個整數的函式。而且要盡量做到使字串對應唯一的hash值。
它的主要思路是選取恰當的進製,可以把字串中的字元看成乙個大數字中的每一位數字,不過比較字串和比較大數字的複雜度並沒有什麼區別(高精數的比較也是o (
n )的),但只要把它對乙個數取模,然後認為取模後的結果相等原數就相等,那麼就可以在一定的錯誤率的基礎上
o (1)
進行判斷了。
hash的實現方法:
首先不要把任意字元對應到數字0,比如假如把a對應到數字0,那麼將不能只從hash結果上區分ab和b(雖然可以額外判斷字串長度,但不把任意字元對應到數字0更加省事且沒有任何***),一般而言,把a-z對應到數字1-26比較合適。
關於進製的選擇實際上非常自由,大於所有字元對應的數字的最大值,不要含有模數的質因子(那還模什麼),比如乙個字符集是a到z的題目,選擇27、233、
19260817
都是可以的。
模數的選擇(盡量還是要選擇質數):
絕大多數情況下,不要選擇乙個
109
級別的數,因為這樣隨機資料都會有hash衝突,根據生日悖論,隨便找上
√10
9
個串就有大概率出現至少一對hash 值相等的串(參見bzoj 3098 hash killer ii)。
最穩妥的辦法是選擇兩個
109
級別的質數,只有模這兩個數都相等才判斷相等,但常數略大,**相對難寫,目前暫時沒有辦法卡掉這種寫法(除了卡時間讓它超時)(參見bzoj 3099 hash killer iii)。
如果能背過或在考場上找出乙個
101
8級別的質數(miller-rabin),也相對靠譜,主要用於前一種擔心會超時,後一種擔心被卡。
偷懶的寫法就是直接使用unsigned long long,不手動進行取模,它溢位時會自動對26
4進行取模,如果出題人比較良心,這種做法也不會被卡,但這個是完全可以卡的,卡的方法參見bzoj 3097 hash killer i。
//雙hash#include #include #include using namespace std;
typedef unsigned long long ull;
ull base=131;
struct data
a[10010];
char s[10010];
int n,ans=1;
ull mod1=19260817;
ull mod2=19660813;
ull hash1(char s)
{ int len=strlen(s);
ull ans=0;
for (int i=0;i#include #include using namespace std;
typedef unsigned long long ull;
ull base=131;
ull a[10010];
char s[10010];
int n,ans=1;
ull mod=212370440130137957ll;//是質數!!
ull hashs(char s)
{ int len=strlen(s);
ull ans=0;
for (int i=0;i
雜湊學習筆記
雜湊錶用的是陣列支援按照下標隨機訪問資料的特性,所以雜湊表其實就是陣列的一種擴充套件,由陣列演化而來。可以說,如果沒有陣列,就沒有雜湊表。它是乙個函式。我們可以把它定義成hash key 其中 key 表示元素的鍵值,hash key 的值表示經過雜湊函式計算得到的雜湊值。三點雜湊函式基本要求 開放...
雜湊學習筆記
考慮具有以下形式的方程 a1x13 a2x23 a3x33 a4x43 a5x53 0 係數是從區間 50,50 起的整數。考慮解決方案 x1,x2,x3,x4,x5 來驗證方程xi 50,50 xi!0,任何i 確定滿足給定方程的解數。輸入項 輸入的唯一行包含由空格分隔的5個係數a1,a2,a3,...
雜湊學習筆記
大概日後會更新 零.hash的用途 在資料範圍不大的時候,你完全可以用乙個map或者set來搞定 如果可以用c 11,你還可以用undered map來搞定 然鵝map也是hash實現的 所以當資料範圍很大 你莫得c 11 出題人毒瘤的時候,就需要雜湊 為了愉快的進行hash,下面煮的栗子預設出題人...