字符串哈希


字符串哈希把字符串变为一个哈希值,可以线性的比较字符串是否相等
时间复杂度 : 预处理 \(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;
}









posted @ 2025-03-25 21:01  he_jie  阅读(37)  评论(0)    收藏  举报