Hash

Hash适用情况:

e.g.给出一列正数(可以是很大很大的数),问没有重复出现的数有多少个?

【分析】你想用数组吗? 那么下标开多大呢?这是不是个十分严峻的问题?so,我们将利用神奇的Hash来进行一个数列的化简。

PS:由于Hans等级太低,只会写最low的Hash,此文将不断更新。

我们利用一个比较迷的质数10007作为modd,每次将数字对它取模。

但是这样就造成了1%10007==10008%10007【淌血】是不是感觉撞上了事情就不好处理了?NO!

我们可以将所有的模数0~10007建成一列结构体二维不定长数组link[i][j]来存放模数相同的数。(太迷了)

具体一点就是结构体里定义num,cnt;num表示的是具体的数值,cnt表示该数值出现的个数。定义link[i][j]表示模数为i的第j个数。

然后每次输入一个数值,计算出它的模数,接着将该模数的不定长数组全部过一遍:①遇到一样的num就cnt++并推出;②遇不到一样的num就在结尾push_back一个新的数。

最后so easy啦!统计所有的cnt就好了!


#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

#define modd 10007


struct node {
	int num;
	int cnt;
};
vector<node> link[modd];

int main(){
	int n, flag, ans = 0;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		node x;
		x.cnt = 1;
		scanf("%d", &x.num);
		int y = x.num % modd;
		flag = 0; 
		for(int j = 0; j < link[y].size(); j++){
			if(x.num == link[y][j].num){
				link[y][j].cnt++;
				flag = 1;
				break;
			} 
		}
		if(!flag){
			link[y].push_back(x);		
		}
	}
	for(int i = 0; i < modd; i++)
	  for(int j = 0; j < link[i].size(); j++)
		 if(link[i][j].cnt == 1) ans++;
		 
	printf("%d\n", ans);
	return 0;
}

字符串版的Hash:

e.g.同样的求多组串中没有重复出现的串个数。

【分析】只要知道如何实现字符串和其对应的模数的转换就OK了,以下change函数将为大家展示转换过程。简单来说就是字符串转成26进制形式,再一次次的对10007取模以防万一就好了~(考虑到Hash的特殊性,顺序什么的都毫无意义啦,只要是一样的数,对应模数就会相同,同时不用考虑模数撞上,因为咱们是用不定长数组存的呀~)


#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

#define modd 10007

struct node {
	char sss[105];
	int cnt;
};
vector<node> link[modd];

int change(char ss[105]){
	int tot = 0;
	for(int i = 0; i < strlen(ss); i++){
		tot = (tot * 26 + (ss[i]-'a')) % modd;
	}
	return tot;
}
char s[105];

int main(){
	int n, flag, ans = 0;
	scanf("%d", &n);
/*	char ch[3] = "zy";
	printf("%d\n", change(ch));
*/	for(int i = 1; i <= n; i++){
		scanf("%s", s);
		node x;
		strcpy(x.sss, s);
		//puts(x.sss);
		x.cnt = 1;
		int y = change(s);
		flag = 0; 
		for(int j = 0; j < link[y].size(); j++){
			if(!strcmp(x.sss, link[y][j].sss)){
				link[y][j].cnt++;
				flag = 1;
				break;
			} 
		}
		if(!flag){
			link[y].push_back(x);		
		}
	}
	for(int i = 0; i < modd; i++)
	  for(int j = 0; j < link[i].size(); j++)
		 if(link[i][j].cnt == 1) ans++;
		 
	printf("%d\n", ans);
	return 0;
}


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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值