哈希
核心公式:hash[i]=(hash[i-1]*p+idz(s[i]))%k
注:为防冲突 p 取1e9+7,k 取1e9+9(减小冲突概率)
还可做双哈希 hash[][],用 make_pair< , >
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 华丽的分割线
idz( )函数是将这个字符转换成一个数,如 ‘a’ --> 1 、‘b’ --> 2 、‘c’ --> 3 ······
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 华丽的分割线
最基础的一道题:
有n个单词,拿单词 s[1],s[2],s[3],...s[n]与 s[0] 比较,求有多少个完全与 s[0] 相同的单词(不含 s[0])。
代码:
#include <bits/stdc++.h> //OK---撒花!!!
using namespace std;
const int MAXN=1e6+10;
int n,ans=0,hash[MAXN],tot;
int p=1e9+7,k=1e9+9; //p和 k通常取一对很大的孪生素数 注:p和 k是<int>类型的!
char s[MAXN];
int idz(int x){ //把单个字符(英文字母)转换成一个数 如 a->1 , b->2 ······
x=x-'a'+1;
return x;
}
int main (){
scanf("%d",&n);
getchar(); //注:用 getchar()可以输入换行 !
gets(s);
int str1=strlen(s);
hash[0]=idz(s[0])%k;
for (int i=1;i<str1;i++){
hash[i]=hash[i-1]*p+idz(s[i])%k; //把 s 的每一位转换成一个数 ,都跟前一位有关系,所以避免重复
//cout<<hash[i]<<" ";
}
cout<<endl;
int tot=hash[str1-1]; //最后一位代表了前面的所有位,是由前面推来的。
//cout<<" "<<tot<<endl;
for (int j=1;j<=n;j++){
gets(s);
int len=strlen(s);
hash[0]=idz(s[0])%k;
//cout<<idz(s[0])<<":"<<hash[0]<<" ";
for (int i=1;i<len;i++){
hash[i]=hash[i-1]*p+idz(s[i])%k;
//cout<<hash[i]<<" ";
}
if(hash[len-1]==tot)ans++; //如果,它的最后一位与 tot 相等,那么它们两个字符数组都将相等。
cout<<ans<<endl;
}
cout<<ans<<endl;
return 0;
}
一直被困扰的问题、小错误:
1)字符的格式化输入仍不熟悉,一开始电脑会把换行读进去
解决办法:用 getchar();
2)字符数组的每一位只能是一个字符,多个字符数组不能混为一体!
3)字符数组是从0开始计的,最后一位应为数组长-1!
4)一开始把 k 用进了这个循环:for (int j=1;j<=n;j++) ,k 这个变量名已经用了,导致最后算 hash 时出错了。
总结:太粗心啦!!!!!