首先,让我们来借用这道题来了解一下哈希算法如何来寻找相同字符串:
我们从这道题中可得知:该题是很普通的一个寻找不同亦或说相同字符串的题,所以使用逐个比较的方法是可以得到正确结果的,例:
#include<iostream>
using namespace std;
string a[10002];
int n;
int ans;
bool m;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
for(int j=1;j<=i-1;j++){
if(a[i]==a[j]){
m=1;
break;
}
}
if(m==0){
ans++;
}else{
m=0;
}
}
cout<<ans;
return 0;
}//代码极丑,大神勿喷
上述代码可以很好地解决这个问题(好吧,作者也承认这道题用这个过不去),但是此时的复杂度却远超哈希排序的复杂度(此处约等于O(n^2))而哈希排序却可以很好地缩减它的复杂度至O(nK)注:此处的K为最长字符串长度。
我们先观摩一下hash排序的伟岸:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int prime=131;
long long mod1=10099757,mod2=10099759;
int hash(char c[]) {
int b=strlen(c);
long int ans=0;
long int ans1=0;
for(int i=1; i<=b; i++) {
ans+=(ans*prime)%mod1+(int)c[i];
ans1+=(((int)c[i]*179)+(int)c[i])%mod2;
}
return ans+ans1;
}
long int e[400002];
bool d[1000002];
char a[1000002];
int main() {
int n;
int sum=1;
cin>>n;
for(int i=1; i<=n; i++) {
scanf("%s",a);
e[i]=hash(a);
// cout<<e[i]<<endl;
}
sort(e+1,e+n+1);
for(int i=2; i<=n; i++) {
if(e[i]!=e[i-1]) {
sum++;
}
}
cout<<sum;
return 0;
}
此处使用的是单hash不是双hash,因为考虑到有的题或是在实践应用中,我们可以考虑使用3hash,因为这样可以报证重复率接近0(当然,此处你需要保证你的hash足够复杂)。
上面扯了那么多,我们现在来看一下什么是hash算法:
首先,我们会先获取几个字符串,例:
ndsisk
16546
nskivn
ndsisk
123546
cdkl
cdkl
看到上面的字符串后,要求去除重复字符串,输出剩下字符串的个数,此时大多数人会先考虑第一种算法,但是,重点来了:如果我有1000000个字符串怎么办,很明显那样的话第一个算法不经调整确实与第二个算法相形见绌,现在就说一下第二个算法的实现,首先我们需要获取这些字符串,然后我们要用一种独特的方式来获取这个字符串所映射出的哈希值,当然这个哈希值只能由唯一 一个字符串得到(不过似乎这不可能诶)例:
int hash(char a[]) {
int len=strlen(a);
int ans=0;
int prime=15797;
int e=131;
int mod=10000004;
for(int i=1; i<=len; i++) {
ans+=(ans*e+prime)%mod+(int)a[i];
}
return ans;
}
这个“ans+=(ans*e+prime)%mod+(int)c[i];”就是为了求独特哈希值的方法。
这个哈希值可以说是相对独立却又不是完全独立的,在某种角度上来讲肯定会有另外一个字符串与其拥有相同的哈希值所以,此时我们需要再引进一个新的求哈希值的方法,之后就变成了这样:
int hash(char a[]) {
int len=strlen(a);
int ans=0;
int ans1=0;
int prime=15797;
int e=131;
int e1=179;
int mod=10000004;
int mod2=10000007;
for(int i=1; i<=len; i++) {
ans+=(ans*e+prime)%mod+(int)a[i];
ans1+=(((int)a[i]*179)+(int)a[i])%mod2;
}
return ans+ans1;
}
这样的话可以让这个所求的哈希值更加的独立。
现在说完求哈希值的方法,而后就要用它来干一些实际上的事,例如还是刚才那到道题:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int prime=131;
long long mod1=10099757,mod2=10099759;
int hash(char c[]) {
int b=strlen(c);
long int ans=0;
long int ans1=0;
for(int i=1; i<=b; i++) {
ans+=(ans*prime)%mod1+(int)c[i];
ans1+=(((int)c[i]*179)+(int)c[i])%mod2;
}
return ans+ans1;
}
long int e[400002];
bool d[1000002];
char a[1000002];
int main() {
int n;
int maxn=0;
int sum=1;
cin>>n;
for(int i=1; i<=n; i++) {
scanf("%s",a);
e[i]=hash(a);
// cout<<e[i]<<endl;
}
sort(e+1,e+n+1);
for(int i=2; i<=n; i++) {
if(e[i]!=e[i-1]) {
sum++;
}
}
cout<<sum;
return 0;
}
这段代码的程序其实非常易读,主旨就是讲哈希值运用快速排序排序完后统计一下出现过的不同的哈希值的数量,这就是一个很简单的哈希值排序。