一种字符串哈希方法 与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;
}
而因为这种很高进制的数可以变得很大,所以我们用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;
}
相关文章推荐
- 字符串根据多个字符进行分割的一种方法(使用split而不是regex.split更不是replace)
- 将字符串按指定字符截断分组的一种方法
- C++中字符串取一个字符的一种方法
- Golang编程实现删除字符串中出现次数最少字符的方法
- 2.7推荐的字符和字符串处理方法
- python清除字符串里非数字字符的方法
- C#实现字符串按多个字符采用Split方法分割
- js replace(a,b)之替换字符串中所有指定字符的方法
- 黑马程序员——获取字符串中相同字符个数的方法
- 一种巧妙的反转字符串的方法及思考过程
- 截取字符串的部分字符方法
- PHP获取一个字符串中间一部分字符的方法
- js中字符串处理常用的方法(字符分割、字符拼接、截取字符串、是否包含一个字符串)
- 字符串替换Replace仅替换第一个字符串匹配项
- jquery 删除字符串最后一个字符的方法解析
- C++中一种输入字符串的方法
- 我的java之路——按照电话机表盘数字与字符的对应关系(这里用数字1而不是0代表空格),用数字串匹配字符串
- java笔试中字符串翻转的几种方法(java---华为----字符逆序)
- string方法 PadLeft 返回一个新字符串,该字符串通过在此实例中的字符左侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符右对齐。 PadRight 右边
- oracle split 字符串的一种方法