哈希
簡單來說,哈希相當於一種單向加密,一種映射過程,並且要盡量保證加密后不會重復,通過這種方式來替代一些很費時間的操作
字符串哈希 也叫進制哈希
當你想判斷兩個字符串是否相等時,不知道你有沒有過一種想法,將兩個字符串通過一些獨特方式的計算轉換成兩個數字,然后判斷兩個數是否相等不就好了,那么進制哈希就提供了一種轉換方式——將這個字符串看成一個base進制的數,因為進制計算的特殊性,可以保證每個數都代表這一種字符串的情況
當然,你可能會有疑問 當字符串是s1“100000”和s2“50000”,base=5時 算出的結果是('1'-'0')*5^5與('5'-'0')*5^4的答案是相同的(這里方便理解-了‘0’然鵝與找到ASCII表中相差4倍的情況相同)但由於進制的特殊性, 滿base進一,所以這種情況被pass了,我們無法控制給出的數據 但我們能改變base值,所以在實際應用中 要讓base大於所有能出現的字符的可能,ASCII碼最大為127 而大於127的最小質數為131,所以一般base取131即可。
base的情況解決了,但如果字符串的長度太大,一般的 int 甚至是long long 都有可能存不下,所以我們可以通過對這個數取模來解決,但他還是有個弊端——兩個不同的數對mod取余后得到的數是一樣的!!這就導致了傳說中的哈希沖突……
我們設置進制(base)為131,模數(mod)為1e9+7,現在我們對一個字符串s進行哈希
1 char s[10009]; 2 scanf("%s",s+1); 3 int len=strlen(s+1); 4 int base=131,mod=1e9+7; 5 for(int i=1;i<=len;i++) 6 { 7 hash[i] = ( ( hash[i-1] * base ) + s[i] ) % mod ; 8 }
借用這張圖片更為直觀
因為哈希的處理是一個字符一個字符的而且計算具有規律性,所以我們還可以取到子串的hash值
hash[l,r] = ( hash [r] - hash[l-1] * fpow(base,r-l+1) ) %mod
//fpow(base,r-l+1)為base的(r-l+1)次方
如何處理哈希沖突??
1.模數選取大質數
如果選取合數那么他的剩余系將會有所浪費,如果質數過小將會導致剩余系過小,哈希沖突幾率增大
/* 所謂“剩余系”,就是指對於某一個特定的正整數n,一個整數集中的數模n所得的余數域。*/
2.雙模數哈希
我們可以通過設置兩個不同的哈希方式,對於一個字符串,當且僅當兩個哈希值都相同時才判定相當。
這就相當於是雙重加密,應該就很靠譜了吧。