字符串哈希
字符串哈希把字符串变为一个哈希值,可以线性的比较字符串是否相等
时间复杂度 : 预处理 \(O(n)\),查询 \(O(1)\)
样例
typedef unsigned long long ull;
cosnt int p = 131;
ull get(string &s) {
ull res = 0;
for (auto &i : s) {
res *= p;
res += i;
}
return res;
}
以上是最简单的样例,基本上字符串哈希是这样的,更详细的可以看 oi-wiki
字符串哈希可以和前缀和联用
在哈希构成的 \(p\)进制数里面,字符串前面的字符占据高位,后面的占据低位
在对前缀和进行查询操作时
将左边的前缀和做“左移”操作( \(\times p^{r - l + 1}\))
与右边的前缀和“对齐”后,相减得到的就是区间中的字符串哈希值
有时,如果字符串有某种单调性,可以用二分进行判断
例题
最长回文子串
允许k次失配的字符串匹配(ps:洛谷里做的第一道紫题)
第二道例题用的写法比较有趣,粘贴上来
允许k次失配的字符串匹配 代码
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int p = 131;
void solve() {
string s, str;
cin >> s >> str;
vector<ull> a(s.size() + 1), b(str.size() + 1), P(s.size() + 1);
P[0] = 1;
for (int i = 0; i < s.size(); i ++) {
a[i + 1] = a[i] * p + s[i];
P[i + 1] = P[i] * p;
}
for (int i = 0; i < str.size(); i ++) {
b[i + 1] = b[i] * p + str[i];
}
auto check = [&](int l1, int l2, int len) ->bool{
auto A = a[l1 + len - 1] - a[l1 - 1] * P[len];
auto B = b[l2 + len - 1] - b[l2 - 1] * P[len];
return A == B;
};
int ans = 0;
for (int i = 1; i + str.size() - 1 <= s.size(); i ++) {
int l, r;
int x = 1, cnt = str.size();
for (int j = 0; j < 4; j ++) {
l = 0, r = cnt;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(i + x - 1, x, mid)) l = mid;
else r = mid - 1;
}
x += l + 1;
cnt -= l + 1;
}
if (cnt < 0) ans ++ ;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int q;
cin >> q;
while (q --) {
solve();
}
return 0;
}