[toc]ios
# 如下內容做廢,太多錯誤了,等我有時間重寫算法
說一下什麼是Hash,說白了就是把一大坨字符用一些神奇的數來表示,能夠說是把字符加密了.函數
簡單一點就是一個像函數同樣的東西,你放進去一個值,它給你輸出來一個值。輸出的值就是Hash值。通常Hash值會比原來的值更好儲存(更小)或比較。加密
字符串hash的靈魂就是儘可能讓不一樣的字符串對應惟一的hsah的值 .而要實現這一效果就要選對方法不然就咕咕咕了spa
舉個栗子:code
若是咱們的加密方法是把字符的ascal加起來,那就咕咕咕了.xml
好比:blog
ababa字符串
babaaget
加起來是同樣的,咕咕咕....
因此應該怎麼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
送上一道模板題:
如題,給定N個字符串(第i個字符串長度爲Mi,字符串內包含數字、大小寫字母,大小寫敏感),請求出N個字符串中共有多少個不一樣的字符串。
輸入格式:
第一行包含一個整數N,爲字符串的個數。
接下來N行每行包含一個字符串,爲所提供的字符串。
輸出格式:
輸出包含一行,包含一個整數,爲不一樣的字符串個數。
時空限制: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就