一、算法原理
我们不直接比较字符串 \(S\) 的字串和模式串 \(T\) 是否相等,而是比较二者的哈希值。
设字符串 \(S\) 的长度为 \(l\),字符串 \(T\) 的长度为 \(m\)。
取两个互素的常数 \(b\) 和 \(h\) (\(l < b < h\)),设字符串 \(C = c_1c_2...c_m\),则哈希函数为:
其中 \(b\) 是哈希基数,相当于把字符串看作 \(b\) 进制数(,哈希函数就是将 \(b\) 进制转换为十进制)。
滚动哈希:这是一种优化技巧,用于优化字符串的匹配。
字符串 \(S\) 从下标 \(k + 1\) 开始的长度为 \(m\) 的子串,它的哈希值为 \(H(S[k + 1, k + m])\);字符串 \(S\) 从下标 \(k\) 开始的长度为 \(m\) 的子串,它的哈希值为 \(H(S[k, k + m - 1])\)。二者的关系为:
证明:
\[\begin{split} H(S[k + 1, ..., k + m])&=(s_{k+1}b^{m-1}+s_{k+2}b^{m-2}+...+s_{k+m}b^0) \text~{mod}~h\\ \\ H(S[k, k + m - 1])&=(s_kb^{m-1}+s_{k+1}b^{m-2}+...+s_{k+m-1}b^0) \text~{mod}~h \\ H(S[k, k + m - 1]) \times b&=(s_kb^{m}+s_{k+1}b^{m-1}+...+s_{k+m-1}b^1) \text~{mod}~h \\ H(S[k, k + m - 1]) \times b - s_kb^m + s_{k + m}&=(s_{k+1}b^{m-1}+s_{k+2}b^{m-2}+...+s_{k+m}b^0) \text~{mod}~h\\ \\ \therefore H(S[k + 1, ..., k + m]) = (H(S[k, &k + m - 1]) \times b - s_kb^m + s_{k + m})~\text{mod}~h \end{split} \]二、代码
typedef unsigned long long ull;
const ull B = 1e9 + 7;
// 计算字符串a的哈希值
ull h(string a)
{
ull ah = 0;
for (int i = 0; i < a.size(); i++) ah = ah * B + a[i];
return ah;
}
// a是否在b中出现
bool locate(string a, string b)
{
// a比b长,a不可能在b中
int al = a.size(), bl = b.size();
if (al > bl) return false;
// 计算B的al次方
ull t = 1;
for (int i = 0; i < al; i++) t *= B;
// 计算a和b长度为al的前缀对应的哈希值
ull ah = 0, bh = 0;
ah = h(a), bh = h(b);
// 右移窗口,更新哈希值并判断
if (bh == ah) return true;
for (int i = 1; i + al < bl; i++)
{
bh = bh * B + b[i + al] - b[i] * t;
if (bh == ah) return true;
}
return false;
}
注:
- 这里哈希基数为素数
1e9 + 7
,它还有一个孪生素数1e9 + 9
。
完
标签:ah,al,算法,哈希,text,字符串,mod From: https://www.cnblogs.com/hoyd/p/18019876