18908 字符串哈希
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC
Description
(1)这一段是乱七八糟的教学模块,看不清楚就百度吧。 字符串哈希可以用于快速比较两个字符串是否相等,或者快速找到子串t在主串s中的位置(模式匹配)。 在完成预处理之后,比较任意两个字符串相等的复杂度O(1)。模式匹配的复杂度和kmp算法接近,为O(n+m)。 那么如何为字符串设计哈希函数呢? 最简单的方法:把字符串直接映射为整数比如abcd看成1234,ccbb看成是3322,考虑到字符串的长度,这样的哈希函数显然不可行。 在前一种设计的基础上,一种容易想到的哈希法是求和,比如f(abcd)=1+2+3+4=10,f(ccbb)=3+3+2+2=10。但这样设计哈希函数非常容易冲突。 通用的方法,取一固定值P,把字符串看作P进制数,并分配一个大于0的数值,代表每种字符。 一般来说,我们分配的数值都远小于P。例如,对于小写字母构成的字符串,可以令a = 1 , b = 2 , . . . , z = 26 。 取一固定值M,求出该P进制数对M的余数,作为该字符串的Hash值。 这样f(abcd)=1*p^3+2*p2+3*p+4,f(ccbb)=3*p^3+3*p2+2*p+2。这种方法如果两个字符串不相同,他们的哈希值相同的概率极小。 当然,这样的哈希函数,应该很容易想到的问题是字符串哈希函数的值很容易就会超过int范围。 此处的技巧是,如果我们不给定余数M的话,超过2^32的部分因为超过了int范围,会自动舍掉(相当于对2^32取余). 稳妥起见,字符串哈希一般采用unsigned long long 类型。 在比较多个字符串是否存在两个相等字符串时,可以采用上述方法求出每个字符串的哈希值,再看看是否有相同值。 在作子串处理或模式匹配问题时,我们需要快速找到子串的哈希值,一般是采用数组的方式来处理。 在字符串哈希数组里,通过一个简单的公式计算就能得到子串的哈希值。
思路记录:字符串哈希,说白了就是用一个更大的进制数来代替原有的字母,因为是为了防止哈希冲突,我们必须要用足够大的数据进制(起码比26大)去代替,小的话很容易产生哈希冲突,这题目数据比较小,26进制也能过,不过一般是取131,1331,13331这些数。判断两个区间的哈希码是否相同即可判断两个区间的字符串是否相等,因为哈希码很大,默认用long long 去纯的话其实是会溢出(即存放的是模运算后的结果),为了可以快速去计算两个区间哈希码,可以运用前缀和(感觉更像前缀积,差不多就这个意思)的思想,就是比如说输入的字符串是“abcdefg”,在计算的过程中也可以把a,ab,abc,abcd,abcdef,abcdefg的哈希码全部计算出来,后面比如说要求cd的哈希码就是通过abcd和ab之间的关系求出哈希码,达到快速运算的效果,因为区间之间的距离可能很大,所以得提前算一下距离之间的积用p数组预处理一下
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<set>
#include <vector>
#include<algorithm>
typedef unsigned long long ll;
using namespace std;
const ll HASH_CONSTAN=131;
ll p[100005]={1},hash_code[100005];
int main(){
ios::sync_with_stdio(false);
for(int i=1;i<=100005;i++)
p[i]=p[i-1]*HASH_CONSTAN;
string s;
cin>>s;
for(int i=0;i<s.size();i++)
hash_code[i+1]=hash_code[i]*HASH_CONSTAN+s[i];
int n;
cin>>n;
int l1,r1,l2,r2;
while(n--){
cin>>l1>>r1>>l2>>r2;
(hash_code[r1]-hash_code[l1-1]*p[r1-l1+1])==(hash_code[r2]-hash_code[l2-1]*p[r2-l2+1])?cout<<"Yes"<<endl:cout<<"No"<<endl;
}
return 0;
}