codevs3013单词背诵--字符串哈希,线型探测哈希

听了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

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值