字符串哈希 模板

如果我们需要统计一个模板串在文本串中出现的次数,该怎么做捏?

首先我们很容易想到暴力,也很容易写出暴力代码

代码如下:

#include <bits/stdc++.h>

using namespace std;

int countOccurrences(const string & text, const string & pattern)
{
    int m = pattern.length(),n = text.length(),count = 0;
    for (int i=0;i-m<=n;++i){
    	int j; 
        for (j=0;j<m;++j) if (text[i+j]!=pattern[j])break;
        if (j == m) count++;
    }
	return count;
}
int main()
{	
    string text = "abcbabcabcabc";
    string pattern = "abc";
    
    int occurrences = countOccurrences(text, pattern);
    cout << "模板串在文本串中出现的次数为:" << occurrences << endl;
    return 0;
}

运行结果如下:

但是,时间复杂度为O(n*m),很慢,所以我们使用字符串哈希进行比较。

字符串哈希的基本原理就在于,计算机比较字符串慢,比较数字快,所以说将字符串哈希映射成数,再比较数字就更快了。

但是在映射的过程中,会出现冲突的情况,所以我们所设计及的哈希函数就要避免大部分冲突,

(当然还是有很多大佬,出的数据可以卡单双哈希,就不得不寻找其他方法来解题)。

这里我使用的是自然溢出法,就可以不用做取模。

求字符串的哈希值的代码如下:

unsigned long long str_hash(const string & a)
{
	unsigned long long ans = a[0];
	int len = a.size();
	for(int i=1;i<len;i++) ans = ans*P+a[i];
	return ans;
}

P 取得一个数,最好是质数,减少哈希冲突。

但是如果是一个字符串我们求它所有前缀的哈希值呢?我们需要用到滚动哈希

创建一个pre数组来存前缀的哈希值,就类似于前缀合之类的。代码如下:

using ull = unsigned long long;

const int N = 1e6+5;
const int P = 13331;

ull pre[N];
ull p[N];
void strhash(const string & x)
{
	int len = x.size();pre[0] = x[0];p[0] = 1;
	for(int i=1;i<len;i++){ pre[i] = pre[i-1] * P + x[i] ; p[i] = p[i-1]*P; }
}

当然p数组可以用pow函数来解决,或快速幂。相信作为大佬的你已经看懂了这个程序。

还有一个问题就是我如果想求字串而并非前缀的哈希值呢?

假设我们的哈希函数可以把“12345”这个字符串转换成整数12345,对应的“123”就是123,那我要求“234”这个字串的哈希值就是234,如下图:

可得程序:

ull get_sonstr(int l,int r)
{
	if(l==0) return pre[r];
	return pre[r] - pre[l-1] * p[r-l+1]; 
}

当l==0时就是求前缀,需要单独处理。

那么哈希的三个基本函数作为大佬的你一定理解了吧!

去练习一下吧!

[USACO12DEC] First! G - 洛谷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值