首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用后缀自动机的最长公共子串

使用后缀自动机的最长公共子串
EN

Stack Overflow用户
提问于 2014-03-16 20:18:02
回答 1查看 2K关注 0票数 2

根据需要使用动态规划O(m * n)、后缀树O(m + n)、后缀数组O(nlog^2 n)计算最长的公共子串。最近,我学习了后缀自动机,它在O(n)中执行,非常令人印象深刻。

我可以编写代码,通过它可以轻松地计算最长的公共子字符串的长度。例如:

代码语言:javascript
复制
Input:
abcdef
xyzabc

Output:
3

这是密码:

代码语言:javascript
复制
#include <bits/stdc++.h>
using namespace std;

const int maxN = 250500;
const int maxState = maxN << 1;

struct State {
    State *go[26], *suffix;
    int depth, id;
    long long cnt;
};
State pool[maxState], *point, *root, *sink;
int size;

State *newState(int dep) {
    point->id = size++;
    point->depth = dep;
    return point++;
}

void init() {
    point = pool;
    size = 0;
    root = sink = newState(0);
}

void insert(int a) {
    State *p = newState(sink->depth+1);
    State *cur = sink, *sufState;
    while (cur && !cur->go[a]) {
        cur->go[a] = p;
        cur = cur->suffix;
    }
    if (!cur)
        sufState = root;
    else {
        State *q = cur->go[a];
        if (q->depth == cur->depth + 1)
            sufState = q;
        else {
            State *r = newState(cur->depth+1);
            memcpy(r->go, q->go, sizeof(q->go));
            r->suffix = q->suffix;
            q->suffix = r;
            sufState = r;
            while (cur && cur->go[a] == q) {
                cur->go[a] = r;
                cur = cur->suffix;
            }
        }
    }
    p->suffix = sufState;
    sink = p;
}

int work(char buf[]) {
    //printf("%s", buf);
    int len = strlen(buf);
    int tmp = 0, ans = 0;
    State *cur = root;
    for (int i = 0; i < len; i++) {
        if (cur->go[buf[i]-'a']) {
            tmp++;
            cur = cur->go[buf[i]-'a'];
        } else {
            while (cur && !cur->go[buf[i]-'a'])
                cur = cur->suffix;
            if (!cur) {
                cur = root;
                tmp = 0;
            } else {
                tmp = cur->depth + 1;
                cur = cur->go[buf[i]-'a'];
            }
        }
        ans = max(ans, tmp);

    }
    return ans;
}

char ch[maxN];

int main() {
    scanf("%s", ch);
    init();
    int len = strlen(ch);
    for (int i = 0; i < len; i++)
        insert(ch[i]-'a');
    scanf("%s", ch);
    printf("%d\n", work(ch));
    return 0;
}

但是现在我需要打印最长的本身,而不是长度。但是我无法修改我的代码:(如何修改这些代码以打印最长的公共子字符串?)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-03-16 21:27:00

当你在这一行时:

代码语言:javascript
复制
ans = max(ans, tmp);

buf中达到深度tmp的起始位置是i - tmp + 1。现在,您知道了第二个字符串中所有最长的公共子字符串的位置。只需选择任意一个并输出结果。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22442408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档