转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足以解决问题