后缀自动机也是解决字符串问题的常用工具,犀利在O(N)的空间复杂度下存在给定串的后缀以及子串,而且支持在线的操作。

POJ-1509 Glass Beads

题意:求一个字符串的最小表示的开始下标。

分析:其实有一个O(N)的算法专门来解决这个问题,并且实现非常简单,不过后缀自动机同样能够解决这个问题。首先把这个串重复两次,然后从前往后一一将字符加入到后缀自动机中,最后从根开始向下遍历串的长度层即可。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 10005;
char str[N];

struct SAM {
    struct Node {
        int ch[26];
        int f, len;
        void init() {
            f = -1, len = 0;
            memset(ch, 0xff, sizeof (ch));
        }
    };
    Node sn[N<<1];
    int idx, last;
    void init() {
        idx = last = 0;
        sn[idx++].init();
    }
    int newnode() {
        sn[idx].init();
        return idx++;
    }
    void add(int c) {
        int end = newnode();
        int tmp = last;
        sn[end].len = sn[last].len + 1;
        for ( ; tmp != -1 && sn[tmp].ch[c] == -1; tmp = sn[tmp].f) {
            sn[tmp].ch[c] = end;
        }
        if (tmp == -1) sn[end].f = 0; // 所有的上一轮可接受点都没有指向字符c的孩子节点 
        else {
            int nxt = sn[tmp].ch[c];
            if (sn[tmp].len + 1 == sn[nxt].len) sn[end].f = nxt; // 如果可接受点有向c的转移,且长度只加1,那么该孩子可以替代当前的end,并且end的双亲指向该孩子 
            else {
                int np = newnode();
                sn[np] = sn[nxt];
                sn[np].len = sn[tmp].len + 1;
                sn[end].f = sn[nxt].f = np;
                for (; tmp != -1 && sn[tmp].ch[c] == nxt; tmp = sn[tmp].f) {
                    sn[tmp].ch[c] = np;
                }
            }
        }
        last = end;
    }
};

SAM sam;

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        sam.init();
        scanf("%s", str);
        int len = strlen(str);
        for (int i = 0; i < len*2; ++i) {
            sam.add(str[i%len]-'a');
        }
        int p = 0;
        for (int i = 0; i < len; ++i) {
            for (int j = 0; j < 26; ++j) {
                if (sam.sn[p].ch[j] != -1) {
                    p = sam.sn[p].ch[j];
                    break;
                }
            }
        }
        printf("%d\n", sam.sn[p].len-len+1);
    }
    return 0;
}
View Code

相关文章:

猜你喜欢
  • 2021-05-26
  • 2022-02-16
  • 2019-03-14
相关资源
相似解决方案