hash(散列)-----进阶版

hash基础版:https://www.cnblogs.com/techgy/p/15037113.html

对于基础hash里面讲到的对只有大写字母的字符串,它将字符串当作二十六进制的数,然后将其转换为十进制。
如下式子,其中str[i]表示字符串的i号位,index函数将A~Z转换为0~25,H[i]表示字符串的前i个位置的hash值。这样当i取遍0~len-1后,得到的H[len-1]就是整个字符串的hash值。

H[i] = H[i-1] x 26 + index(str[i])

但是这个方法有不足的地方,就是当字符串长度较长时,产生的整数会非常大,可能没办法使用一般的整数类型进行保存。因此为了解决这种情况,只能舍弃一些“唯一性”,将产生的结果对一个整数mod取模,即使用下面的散列函数。

H[i] = (H[i-1] x 26 + index(str[i])) % mod

使用上面的散列函数就可以将字符串转换成范围上能接受的整数。这样会导致冲突。不过,经过实践发现,在int数据范围内,如果把进制数设置为一个107级别的素数p(例如10000019),同时把mod设置为一个109级别的素数(例如1000000007),那么冲突的概率就会变得非常小。

H[i] = (H[i-1] x p + index(str[i])) % mod

问题:给出N个只有小写字母的字符串,求其中不同的字符串的个数。
使用字符串hash来做,那么只需要将N个字符串使用字符串hash函数转换为N个整数,然后将它们排序去重即可(也可以使用set或者map直接一步实现,但是速度比字符串hash会慢一点点)。
代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int MOD = 1000000007;
const int P = 10000019;
vector<int> ans;

long long hashFunc(string str){
	long long H = 0;
	for(int i=0;i<str.length();i++){
		H  = (H*p + str[i] - 'a') % MOD;
	}
	return H;
}

int main()
{
   string str;
	while(getline(cin,str), str != "#"){
		long long id = hashFunc(str);
		ans.push_back(id);
	}
	sort(ans.begin(),ans.end());
	int count = 0;
	fot(int i=0;i<ans.size();i++){
		if(i==0 || ans[i] != ans[i-1])
			count++;
	}
	cout<<count << endl;
   return 0;
}

未完待续...

原文地址:https://www.cnblogs.com/techgy/p/15039772.html