您的位置:首页 > 其它

一种字符串哈希方法 与o(n+m)字符串匹配

2014-04-20 00:03 176 查看
这种字符串哈希方法的基本想法就是把字符串转换成n进制数存起来。以纯英文字母字符串(例如abcdefghijk)为例,可以转换为27进制或更高进制数(31进制或131进制),因为aa与a不同,不能用00和0来区分,所以最少要27进制。

而因为这种很高进制的数可以变得很大,所以我们用unsigned long long 来储存它们。如果所求的值超出了unsigned long long的范围也就是大于2^64-1,就会自动对2^64-1取模。又因为2^64-1实在是太大了,所以除非你人品太差,否则不会出现冲突的。。。

用上述的哈希方法来实现字符串匹配,即判断一个串是否是另一个串的子串。例如大串a和小串b,进制数为base。用一个H[i]存a[a的长度]到a[i]这个子串的哈希值(之所以从后往前存是为了后来匹配的时候从前往后匹配方便,放过来从前往后存其实一样)。用xp[i]来存base的i次方。这样,对任意以i为起点B长度的a的字串,它的哈希值可以表示为 H[i]-H[i+B]*xp[B]
将这个值与b串的哈希值比较看看是不是一样就可以了。 实际上把a串遍历一遍,b串遍历一遍,对比的时候遍历a-b长度次,可以看作是o(n+m)的算法。以下是纯英文字母字符串(只有大写或小写)代码,其余字符串可以改变base值来实现。

#include<iostream>

#include<string>

#include<cstdio>

#include<algorithm>

using namespace std;

typedef unsigned long long ll;

const int maxn=1000005;

const int base=131;

ll H[maxn],xp[maxn];

int main()

{

int i;

xp[0]=1;

for(i=1;i<maxn;++i){

xp[i]=xp[i-1]*base;

}

string a,b;

cin>>a;//输入a串

int A=a.size();

H[A]=0;

H[A-1]=a[A-1]-'a'+1;

for(i=A-2;i>=0;--i){

H[i]=H[i+1]*base+a[i]-'a'+1;

}

while(cin>>b){

int B=b.size();

ll b_num=0;

for(i=B-1;i>=0;--i){

b_num=b_num*base+b[i]-'a'+1;

}

bool flag=1;

for(i=0;i<A-B+1;++i){

ll a_num=H[i]-H[i+B]*xp[B];

if(a_num==b_num){

flag=0;

break;

}

}

if(flag) cout<<"No\n";

else cout<<"Yes\n";

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: