codevs3013单词背诵--字符串哈希,线型探测哈希
来源:互联网 发布:java base64加密乱码 编辑:程序博客网 时间:2024/04/30 00:35
听了zhx的字符串哈希,很有收获,来一发。
最省事的思路当他是map了,第一问,直接Map解决,查询M次的时间复杂度mlog(n),第二问,从左侧找出所以单词的区间,用类似滑动窗口和桶排序处理左右端点。
#include<iostream>#include<string>#include<cstring>#include<map> #include<cmath>using namespace std;const int maxm=100009;int n,m;int b[maxm],cword,fword[1009];map<string,int>mp;void read(){cin>>n;string s;for(int i=1;i<=n;i++){cin>>s;mp[s]=i;}cin>>m;for(int i=1;i<=m;i++){cin>>s;if(mp.count(s)){int tp=mp[s];if(!fword[tp])cword++,fword[tp]=1;b[i]=tp;}else b[i]=0;}cout<<cword<<endl;} int work(){int l=0,r=0,ans=maxm,cnt=0;memset(fword,0,sizeof(fword));while(l<=r){while(r<m){r++;if(b[r]==0){continue;}fword[b[r]]++;if(fword[b[r]]==1)cnt++;if(cnt==cword)break;}while(l<=r){if(b[l]==0){l++;continue;}if(fword[b[l]]>1)fword[b[l]]--,l++;if(fword[b[l]]==1)break;}ans=min(ans,r-l+1);//cout<<"l,r"<<l<<" "<<r<<" "<<ans<<endl;if(r>=m)break;}return ans;}int main(){read();cout<<work()<<endl;}
然后将map改成了个特点简单的哈希,顺便用了m做模数,结果竟然只错了一个点
#include<iostream>#include<string>#include<cstring>#include<map> #include<cmath>using namespace std;const int maxm=100007;int n,m;int a[1007],b[maxm],cword,fword[maxm],hash[maxm];int strhash(string s){int ls=s.length();int val=0;for(int i=0;i<ls;i++)val=(val*107+(s[i]-20))%maxm;return val;}map<string,int>mp;void read(){cin>>n;string s;for(int i=1;i<=n;i++){cin>>s;a[i]=strhash(s);hash[a[i]]=true;}cin>>m;for(int i=1;i<=m;i++){cin>>s;int tp=strhash(s);if(hash[tp]){if(!fword[tp])cword++,fword[tp]=1;b[i]=tp;}else b[i]=0;}cout<<cword<<endl;} int work(){int l=0,r=0,ans=maxm,cnt=0;memset(fword,0,sizeof(fword));while(r<m){while(r<m){r++;if(b[r]==0){continue;}fword[b[r]]++;if(fword[b[r]]==1)cnt++;if(cnt==cword)break;}while(l<=r){if(b[l]==0){l++;continue;}if(fword[b[l]]>1)fword[b[l]]--,l++;if(fword[b[l]]==1)break;}ans=min(ans,r-l+1);//cout<<"l,r"<<l<<" "<<r<<" "<<ans<<endl;if(r>=m)break;}return ans;}int main(){read();cout<<work()<<endl;}
将模数扩大了10倍,然后AC了。
但是zhx说了,应用不要用单模,所有又改成了双模的,第一次写,很丑。
#include<iostream>#include<string>#include<cstring>#include<map> #include<cmath>using namespace std;const int maxm=100007;int mm[2]={99991,100007};int n,m;int a[1007],cword,fword[maxm][2]={0},hasha[maxm][2]={0};struct node{int v1,v0;}v,tv,b[maxm];node strhash(string s){int ls=s.length();tv.v0=0;tv.v1=0;for(int i=0;i<ls;i++){tv.v0=(tv.v0*107+(s[i]-20))%mm[0];tv.v1=(tv.v1*107+(s[i]-20))%mm[1]; }return tv;}void read(){cin>>n;string s;for(int i=1;i<=n;i++){cin>>s;tv=strhash(s);hasha[tv.v0][0]=1;hasha[tv.v1][1]=1;//cout<<tv.v0<<" "<<tv.v1<<endl;}cin>>m;for(int i=1;i<=m;i++){cin>>s; tv=strhash(s);// cout<<"m-- "<<tv.v0<<" "<<tv.v1<<endl;if(hasha[tv.v0][0]&&hasha[tv.v1][1]){if(fword[tv.v0][0]==0&&fword[tv.v1][1]==0)cword++,fword[tv.v0][0]=1,fword[tv.v1][1]=1;b[i]=tv;//cout<<"cw"<<endl;}else b[i].v1=0,b[i].v0=0;//cout<<b[i]<<" ";}cout<<cword<<endl;} int work(){int l=0,r=0,ans=maxm,cnt=0;memset(fword,0,sizeof(fword));while(r<m){while(r<m){r++;if(b[r].v0==0&&b[r].v1==0){continue;}fword[b[r].v0][0]++,fword[b[r].v1][1]++;if(fword[b[r].v0][0]==1&&fword[b[r].v1][1]==1)cnt++;<span style="font-family: Arial, Helvetica, sans-serif;"> if(cnt==cword)break;</span><span style="font-family: Arial, Helvetica, sans-serif;"></span>}while(l<=r){if(b[l].v0==0&&b[l].v1==0){l++;continue;}if(fword[b[l].v0][0]>1&&fword[b[l].v1][1]>1)fword[b[l].v0][0]--,fword[b[l].v1][1]--,l++;if(fword[b[l].v0][0]==1&&fword[b[l].v1][1]==1)break;}ans=min(ans,r-l+1);if(r>=m)break;}return ans;}int main(){read();cout<<work()<<endl;}
hzw在做这个题的时候用了线型探测哈希的方法,顺便理解下。
线性探测法构造哈希表的一个具体例子:
http://blog.163.com/wf_shunqiziran/blog/static/1763072092012612114126231/
已知一组关键字为(39,49,54,38,44,28,68,12,06,77),用除余法构造散列函数,用线性探查法解决冲突构造这组关键字的散列表。
解答:为了减少冲突,通常令装填因子α<l。这里关键字个数n=10,不妨取m=13,此时α≈0.77,散列表为T[0..12],散列函数为:h(key)=key%13。
由除余法的散列函数计算出的上述关键字序列的散列地址为(0,10,2,12,5,2,3,12,6,12)。
前5个关键字插入时,其相应的地址均为开放地址,故将它们直接插入T[0],T[10),T[2],T[12]和T[5]中。
当插入第6个关键字15时,其散列地址2(即h(15)=15%13=2)已被关键字41(15和41互为同义词)占用。故探查h1=(2+1)%13=3,此地址开放,所以将15放入T[3]中。
当插入第7个关键字68时,其散列地址3已被非同义词15先占用,故将其插入到T[4]中。
当插入第8个关键字12时,散列地址12已被同义词38占用,故探查hl=(12+1)%13=0,而T[0]亦被26占用,再探查h2=(12+2)%13=1,此地址开放,可将12插入其中。
类似地,第9个关键字06直接插入T[6]中;而最后一个关键字77插人时,因探查的地址12,0,1,…,6均非空,故77插入T[7]中。
hzw代码在这里:http://hzwer.com/2135.html
- codevs3013单词背诵--字符串哈希,线型探测哈希
- 【CodeVS3013】单词背诵
- codevs3013 单词背诵
- codevs3013单词背诵
- [CodeVS3013]单词背诵 做题笔记
- [codevs3013]单词背诵 二分+尺取
- 哈希背诵用模板
- 单词背诵
- Codevs1013 单词背诵
- 洛谷1381 单词背诵
- PAT--1078. Hashing(哈希二次探测)
- 哈希之线性探测法
- 哈希查找之平方探测
- 哈希冲突的处理【闭散列方法-线性探测和二次探测】
- 浅谈哈希函数与线性探测再散列
- 处理哈希冲突的线性探测法
- 1078. Hashing (25)哈希二次碰撞探测
- 10天背诵英文10000单词
- java面向对象(基础)
- 2016/09/18 print_r函数第二个参数是否使用过,如果用过请说出具体功能
- starUML2.7通用破解教程
- 静态页面制作(二)
- Java.math.BigInteger/Java.math.BigDecimal
- codevs3013单词背诵--字符串哈希,线型探测哈希
- codeforces 377A Maze(dfs)
- BZOJ4000: [TJOI2015]棋盘 解题报告
- noip 2015 day2T2 字串
- Android6.0 Audio系统架构
- 1. Bootstrap简单模板
- LeetCode 382. Linked List Random Node 题解(C++)
- 基于systemVerilog的UVM 调试问题及解决办法集锦
- 写一个程序输入一个数,输出小于这个数的所有素数