序列自动机

序列自动机

序列自动机是一个可以快速判断字符串t是否是字符串s的子序列的一个算法。

序列自动机基础

  1. 初始化:对s构造序列自动机,使用图片说明 代表从第i个位置开始,字符j出现的第一个位置。我们倒着遍历更新即可。
const int maxn = 1e6+1;
const int inf = 0x3f3f3f3f;

char s[maxn], t[maxn];  // 原串与子串
int Nxt[maxn][26]; // 序列自动机的存储

void init(int n) { // 序列自动机初始化
    for(int i = 0; i < 26; ++ i) Nxt[n+1][i] = inf;
    for(int i = n; i >= 1; -- i) {
        for(int j = 0; j < 26; ++ j) {
            Nxt[i][j] = Nxt[i+1][j];
        }
        Nxt[i][s[i]-'a'] = i;
    }
}

序列自动机拓展

  1. 判断 t 是否为 s 的子序列:设置初始指针pos为0,每次让pos跳到图片说明 上面,j为当前查询的字符,如果pos为INF,则说明找不到下一个字符,即t不是s的子序列。
bool check(int m) { // 判断长度为m的子串是否是原串的子序列
    int pos = 0;
    for(int i = 1; i <= m; ++ i) {
        pos = Nxt[pos+1][t[i]-'a'];
        if (pos == inf) return false;
    }
    return true;
}
  1. 计算 s 与 t 的最长公共子序列(时间复杂度 图片说明 ):设 dp[i][j] 表示与 t[1..i] 的公共序列长度达到 j 的 A[1..n] 的最短前缀的长度,利用 Nxt 数组进行转移。 注:m = |t|
int dp[maxn][maxn]; // 以t的第i位结尾,且与s的最长公共子序列长度为j的最小下标

int lcs(int m) { // 序列自动机 + dp 求最长公共子序列
    for(int i = 0; i <= m; ++ i) {
        for(int j = 0; j <= i; ++ j) {
            dp[i][j] = inf;
        }
    }
    dp[0][0] = 0;
    for(int i = 0; i < m; ++ i) {
        for(int j = 0; j <= i; ++ j) {
            dp[i+1][j] = min(dp[i+1][j], dp[i][j]);
            if (dp[i][j] != inf) dp[i+1][j+1] = Nxt[dp[i][j]+1][t[i+1]-'a'];
        }
    }
    int res = 0;
    for(int i = 1; i <= m; ++ i) {
        if (dp[m][i] != inf) res = i;
    }
    return res;
}

专题

http://acm.hdu.edu.cn/showproblem.php?pid=1159 【拓展.3】
http://acm.hdu.edu.cn/showproblem.php?pid=6774 【拓展.3】

字符串 文章被收录于专栏

关于acm竞赛字符串的个人笔记

全部评论

相关推荐

不愿透露姓名的神秘牛友
昨天 11:15
点赞 评论 收藏
分享
半解316:内容充实,细节需要修改一下。 1,整体压缩为一页。所有内容顶格。 2,项目描述删除,直接写个人工作量 修改完之后还需要建议,可以私聊
点赞 评论 收藏
分享
北漂的牛马人:211佬,包进的,可能是系统问题
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务