第2部分 字符串算法(提高篇)--第1章 哈希和哈希表1455:【例题1】Oulipo

1455:【例题1】Oulipo

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 2275 通过数: 857
【题目描述】
给出两个字符串s1,s2((只有大写字母),求s1在s2中出现多少次。

例如:s1=“ABA”,s2=“ABAABA”,答案为2。

【输入】
输入T组数据,每组数据输出结果。

【输出】
如题述。

【输入样例】
3
BAPC
BAPC
AZA
AZAAZAAZA
VEEDI
AVERDXIVYERDLAN
【输出样例】
1
3
0
【提示】
1≤s1的长度 ≤104​​ ,1≤s2的长度 ≤106​ 。


思路:一个字符串s2中匹配s1(找出现的位置或者出现的次数),哈希的大体思想就是将每一段字符串或者大数据用变量直接来表示,这样只要直接比较两段字符串的哈希值,就可以直接判断这两段字符串或者大数据是不是相等。
希算法是通过一个哈希函数,将一段数据(也包括字符串、较大的数字等)转化为能够用变量表示或是直接就可作为数组下标的数字,这样转化后的数值我们称之为哈希值, 也就是算出一个数来代表一个字符串。
我们通过哈希值从而实现很快地查找和匹配,
常用:字符串Hash
字符串Hash流程
如果我们用O(m)的时间来计算长度为m的字符串的哈希值,则总的时间复杂度并没有改观,这里就需要用到一个叫做滚动哈希的优化技巧。
我们选取两个合适的互素常数b(进制)和h(模数)(b < h),假设字符串C =c1c2…cm,那么我们定义哈希函数:
在这里插入图片描述
正常的数字是十进制的,这里b是基数,相当于把字符串看做是b进制数。
这一过程是递推计算的,设H(c, k)为前k个字符的构成的字符串的哈希值,则:(以下均不考虑取模的情况)
在这里插入图片描述
如字符串C=“ACDA”(为方便处理,我们令‘A’表示1,‘B’表示2,以此类推),则:
第2部分 字符串算法(提高篇)--第1章 哈希和哈希表1455:【例题1】Oulipo_第1张图片
判断字符串C 从位置k+1开始的长度为n的子串C’=ck+1ck+2…ck+n的哈希值与另一匹配串S = s1s2…sn的哈希值是否相等,则:
在这里插入图片描述
于是只要预处理出bn,就能在O(1)时间内得到任意的字符串子串哈希值,从而完成字符串匹配,那么上述字符串匹配问题的总复杂度就为O(n + m)。
如字符串C=“ACDA”,S=”CD”,当k=1, n=2时:
第2部分 字符串算法(提高篇)--第1章 哈希和哈希表1455:【例题1】Oulipo_第2张图片
因此子串C’与匹配串S匹配。
在实现时,可以利用64位无符号整数计算哈希值,即取h=2^64,通过自然溢出省去求模运算。
字符串Hash正确性
字符串Hash对于任意不同的字符串所产生的哈希值必然是互不相同的吗?显然不是的,但概率很低,在竞赛中我们常常认为这种情况不会发生。
即便如此,我们还可以再用“双哈希”降低出现相同哈希值的概率,即取不同的模数,把不同模数算出的哈希值都记下来,只有几个哈希值都一样,我们才能判定匹配。我们通常用双哈希就可以将冲突的概率降到很低,如果分别取h=109+7和h=109+9,就几乎不可能发生冲突,因为他们是一对“孪生素数”。

#include
#include
#include
#define ULL unsigned long long
#define k 131
#define maxn 1000005
int n;
char s1[maxn],s2[maxn];
ULL f[maxn],l1,l2,t;
ULL a[maxn];
ULL get(int x, int y){
	return f[y]-f[x-1]*a[y-x+1];
} 
int main(){
	scanf("%d",&n);
	a[0] = 1;
	for(int i = 1; i <= 1000000;i++)
	a[i] = a[i-1]*k;
	for(int i = 1; i <= n;++i)
	{
		int ans(0);t = 0;
		scanf("%s%s",s2+1,s1+1);
		l1 = strlen(s1+1);//第一个字符开始
		l2 = strlen(s2+1);
		for(int j = 1; j <= l1; ++j)//计算主chuan的哈希值
		f[j] = f[j-1]*k+(s1[j]-'A');
		for(int j = 1; j <= l2; ++j)//计算s2的哈希值
		t = t *k + (s2[j]-'A');
		for(int j = 1; j+l2-1 <= l1; ++j){
			if(get(j,j+l2-1) == t)
			ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(信息学C++,一本通)