哈希算法是一种便于查找字符串的算法
模板传送
哈希算法(HASH)其实就是把字符串转化为自己想要的哈希值,这个值由自己的来定义。
列如:
给你一堆字符串,判断里面有多少个回文字符串,听起来很简单是不是?但是要是这个字符串的数据很大,而且你不能用C++函数的辅助呢?(这里是举个列子哈,毕竟哈希的用处很广)这里就很容易超时,这时候我们就要将每个字符串做出一定的处理,使得判断是否为回文的时候只需要O(1)的时间就够了。
正式介绍:
哈希就是把题目给出的字符串,做出一个处理(类似进制转换)。如:给你字符串 abcd 与 abde。我们就可以定义一个int HASH[Size]的数组把每个字符串转化成int类型来存储(因为这样可以直接比较是否相等,字符数组则不行)
哈希值
我们再定义一个进制num = 277(先可以理解为随意定,后面再解释为什么不可以随意)我们就可以这样
char str[4] = "abcd";
int ans = 0;
for(int i = 0;i < 4;i++)
ans = ans * num(转化进制) + (str[i]-'0');
这个ans就是哈希值,再比较俩个字符串的哈希值相不相等就容易了,那么问题随之而来,当字符串很长时,那岂不是要爆掉int了?这里我们就要再定义一个模数mod = 很大的一个数,这样就不会爆掉了(最好开unsigned long long)。
哈希冲突
但是问题还是有,哈希值一样,难道字符串就一点相等吗?(如 3 + 7 = 10 和 5 + 5 = 10 一样)无论多好的哈希处理,都存在哈希冲突,也就是存在这种哈希值相等但是字符串不等的情况。在这里我们就是尽可能的降低这种哈希冲突。
如何降低哈希冲突
与你的进制和模数相关。众所周知,ascill码有230多(应该叭。。没记那么清楚),那么这个进制一定要选得比他大,但是也不是过度的大,257,277,599,1533,2634198563(合理的随意)这些都可以,但是不要选择模数的因数(不然模数怎么模,没意义了)。
接下来就是模数的选择了,最好找一个超级大的质数,(不然很容易被随机数据给卡掉了),这个质数多大呢?最好不要1e9以内,和题的数据很容易冲突,如果能找到一个1e18的质数就是最好的事情了。如19999999999999997等等。
但是,这不代表你不会被卡,只要出题人够狠,再好的哈希等于白给,这里只是讲一种思路,一种转化方法,可以延伸到很多难题上面(伤心,我还是这么的菜)。
模板题很好,建议初学者去做做
这里附上我的模板题代码(看不看都差不多啦。。。)
#include <bits/stdc++.h>
using namespace std;
#define NewNode (TreeNode *)malloc(sizeof(TreeNode))
#define Mem(a,b) memset(a,b,sizeof(a))
const int N = 5e5 + 5;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-10;
const unsigned long long mod = 19999999999999997;
const int II = 3.1415926535;
typedef long long ll;
typedef unsigned long long ull;
ull HASH[10050];
char str[10050];
int num = 279;
ull Hash(char str[])
{
ull ans = 0;
int len = strlen(str);
for(int i = 0;i < len;i++)
ans = (ans*num+(ull)str[i])%mod;
return ans%mod;
}
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%s",str);
HASH[i] = Hash(str);
}
int sum = n;
sort(HASH+1,HASH+n+1);
for(int i = 1;i < n;i++)
if(HASH[i] == HASH[i+1])
sum--;
cout << sum << endl;
}