轉html
http://acm.uestc.edu.cn/#/problem/show/1092ios
一天,韓爺去百度面試,面試官給了他這麼一個問題。面試
給你2萬個字符串,每一個字符串長度都是100,而後把2萬個字符串丟入一個 set< string >g 中,問最終set裏含有多少個元素?
g 是一個用來存儲字符串、具備去重功能的容器,即相同字符串在 g 中只能保留一個。
兩個字符串相等,當且僅當,長度同樣且對應位置的字符都同樣。
韓爺前晚沒睡好,隨手寫了一個程序交給面試官,而後就gg了。安全
#include<iostream> #include<string> #include<set> using namespace std; string s; set<string>g; int main(){ for(int k=1;k<=20000;k++){ cin>>s; g.insert(s); } cout<<g.size()<<endl; return 0; }
韓爺醒來以後,發現這只是一個夢(還好只是個夢)。他回憶起夢中的面試官給他的內存限制和時間限制很是低,這麼作確定過不了,那麼,如今你不在夢中,你能解決這個問題麼?函數
單case測試
每一個case有且只有2萬行,每一行包含一個字符串,每行字符串的長度都爲100 (樣例除外)
spa
字符集:大寫英文字母(A-Z),小寫英文字母(a-z),數字(0-9)code
輸出一個整數,表示最終set裏含有多少個元素。htm
Sample Input | Sample Output |
---|---|
aaAa aaAa bbbb 1234 bbbb bbbb ee09 |
4 |
樣例只是樣例,不在test中
blog
注意時間限制和內存限制很是低
思路:這道題目難點在於時間與內存限制很苛刻,通常的方法不能奏效,這裏只能採用hash。即把每一個字符串hash爲一個數字,對數字進行比對,題目就ac了。還有個問題就是,hash函數的選取。我第一次選的hash函數就產生了衝突,這個能夠屢次選擇進行測試,也能夠直接採用更復雜的hash函數。我偷懶了下,選的是前者的方法,第二發就ac了。
這裏說下關於hash的知識:
求一個字符串的hash值:
假設咱們取p=13 ,mod=101
先把abc映射爲一個整數
hash[0]=1,表示 a 映射爲1
hash[1]=(hash[0]*p+idx(b))%mod=15,表示 ab 映射爲 15
hash[2]=(hash[1]*p+idx(c))%mod=97
這樣,咱們就把 abc 映射爲 97 這個數字了。
hash值呢?
unsigned long long hash[N];
定義一個unsigned long long類型的變量,它的範圍是在[0, 2^64) 內,這就至關於,當數超不過2^64-1後,它會溢出!這就至關於一個數模2^64的過程。
那麼hash函數能夠理解爲:
hash[i]=(hash[i-1]*p)%(2^64)
P取一個大素數,通常習慣取1e9+7或1e9+9
安全指數:三星(因此並非很安全)
這個以前已經提到過了。
hash[i]=(hash[i-1]*p+idx(s[i]))%mod
hash1[i]=(hash1[i-1]*p+idx(s[i]))%mod1
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2
pair<hash1,hash2>表示一個字符串!
解釋:
hash1[i]=(hash1[i-1]*p+idx(s[i]))%mod1
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2
mod1通常取1e9+7,mod2通常取1e9+9爲何這麼取?
1000000007和1000000009是一對孿生素數,取它們,衝突的機率極低!
但請注意,hash的維度越高,耗時越高,耗內存越大!通常狀況下,single hash能夠被hack掉,但double hash極難被hack掉, 用double hash足以解決問題