• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【字符串哈希+二分】AcWing 3508. 最长公共子串

题解

首先思考暴力枚举长度为 \(len∈[1, min(strlen(s), strlen(t))]\),最差情况下为字符串 \(s\) 和字符串 \(t\) 全为长度为 \(10000\) 的全英文字符串,时间复杂度: \(O(n^2)\),显然会超时。

容易证明的是:若存在一个长度为 \(x\) 的公共子串,那么一定能在字符串 \(s\) 和字符串 \(t\) 中找到长度为 \(len∈[1, x - 1]\) 的公共子串。
因此,不妨假设最长的公共子串的长度为 \(x\),我们只需要证明不存在长度为 \(x + 1\) 的公共子串即可。该过程枚举长度 \(x\),满足二分性质。
判断字符串 \(s\) 和字符串 \(t\) 是否存在长度为 \(x\) 的公共子串,可以用字符串哈希来达到快速查找。

参考代码

#include<iostream>
#include<vector>
#include<unordered_set>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
using namespace std;
using ull = unsigned long long;

const int N = 10007;
const int P = 131;
ull p[N];
vector<vector<ull>> h1, h2;
string s, t;
int n, m;

bool judge(char &ch) {
    return ch >= 'a' && ch <= 'z';
}

void init() {
    n = s.size(), m = t.size();
    p[0] = 1;
    for (int i = 1, j = max(n, m); i <= j; ++ i) p[i] = p[i - 1] * P;
    auto func = [&](string& str, vector<vector<ull>>& h, int &len) {
        for (int i = 0; i < len; ++ i) {
            if (judge(str[i])) {
                vector<ull> v = {0ULL};
                int j = i;
                do {
                    v.emplace_back(v.back() * P + str[i] - 'a');
                    ++ i;
                } while (i < len && judge(str[i]));
                h.emplace_back(v);
            }
        }
    };
    func(s, h1, n), func(t, h2, m);
}

ull get(vector<ull>& vec, int l, int r) {
    return vec[r] - vec[l] * p[r - l];
}

int main() {
    IOS
    cin >> s >> t;
    init();
    auto check = [&](int x) -> bool {
        unordered_set<ull> ust;
        for (auto &h: h1) for (int i = x; i < h.size(); ++ i) ust.insert(get(h, i - x, i));
        for (auto &h: h2) {
            for (int i = x; i < h.size(); ++ i) {
                ull val = get(h, i - x, i);
                if (ust.find(val) != ust.end()) return true;
            }
        }
        return false;
    };
    int le = 0, ri = min(n, m), md;
    while (le < ri) {
        md = le + ri + 1 >> 1;
        if (check(md)) le = md;
        else ri = md - 1;
    }
    cout << le << '\n';
    return 0;
}

posted on 2024-11-19 23:17  RomanLin  阅读(49)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3