题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1456
题目描述:往空书架里存书找书
题目思路:看见字符串堆就可以去找哈希了
正常人的思路一般都是一个一个算哈希值,存书架里,要找的时候再遍历
对嘛,反正n<=30000,搜了也没啥大事
但是,哈希表里面的一个原则是“哈希值相同的字符串大概率相同“,可不是一定
而直接比字符串,30000个又不太现实
于是,我们就想到了下面的玩法
以哈希值为进门钥匙,把值相同的东西放在一起,然后依据每个字符串的哈希值进行存和找
这样的话,计算哈希值就可以帮我们分担一部分时间压力
如果以这个思路往下走的话,那就只能把“vector”请出山了
vector可以被理解为是一个表格,我们这次要用的vector如下
表头(哈希值\字符串) | 1号字符串 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ...... |
哈希值为1的 | ...... | ...... | ...... | ||||||||||||||||
...... | ...... | ||||||||||||||||||
11659 | Java | ...... | |||||||||||||||||
...... | ...... | ||||||||||||||||||
21827 | C# | ...... |
比如要存储C#,它的哈希值为21827,那就把他存在21827那一行里
如果要找C#,它的哈希值为21827,那就从21827那一行里找,找到就出“YES”,没找到就算了
在这里还有一个操作就是把某一行一共多少个东西,数量可以给找出来
一般是用 .size() 来找
上面就是基本思路了,接下来众人请看代码行事
#include<vector>
#include<string>
#include<iostream>
using namespace std;
string t,s;int n;//魔鬼细节
//这里必须用string来导,不然会与vector冲突
//天天净是编译错误,本人在这儿死了三遍
vector<string> ks[23335];//定义vector
//vector的表头应该是固定的int
//在<>里面的数据才是决定后面它存的是个什么
inline void add(){
int hh=0;//这里的初值别太大就没问题
//我想定0,1,2,3什么的都可以
for(int i=0;s[i];++i){
if(s[i]==' '){
continue;//空格可以要着也可以不要
//如果要要的话,它的ASCII码是32
}
hh=(hh*111*210+s[i])%23333;//算哈希值
//魔鬼细节
//第一个,它必须要对一个质数取余
//不然vector吃不下
//第二个,它不能直接乘以一个5位数
//要分成两个3位数分别成,不然时间会刚好超限
//本人在这死了十一遍
}
for(int i=0;i<(int)ks[hh].size();i++){
//找到这个哈希值代表的行
//一个一个看
if(ks[hh][i]==s){//看到了
return;//那还往里存干嘛?
}
}
//没看到
ks[hh].push_back(s);//存进去
}
inline void find(){
int hh=0;
for(int i=0;s[i];++i){
if(s[i]==' '){
continue;
}
hh=(hh*111*210+s[i])%23333;
}
for(int i=0;i<(int)ks[hh].size();i++){
//由此处向上皆与上文同理
if(ks[hh][i]==s){//看到了
cout<<"yes"<<endl;//打yes
return;
}
}
//没看到
cout<<"no"<<endl;//打no
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
cin>>t;//先把指令打进来
if(t=="find"){//如果是“寻找”
getline(cin,s);
//把字符串带着空格一起捞进来
find();
}
else{//如果是“存入”
getline(cin,s);
add();
//同理
}
}
return 0;
}
总结:注意细节