博客
关于我
月月查华华的手机(每日一题)序列自动机
阅读量:738 次
发布时间:2019-03-22

本文共 2262 字,大约阅读时间需要 7 分钟。

为了高效解决判断字符串是否为另一个字符串的子序列问题,我们使用前缀自动机(Prefix Automaton)的方法。这种方法在构建前缀自动机过程中,只需线性时间,且每个查询的时间复杂度为O(N),其中N为目标字符串的长度。以下是实现该方法的详细步骤:

1. 前缀自动机构建

  • 初始化数组

    • 定义一个二维数组 nex,大小为 N+1 行和26列,用于存储状态转移关系。
    • 初始化 nex[N][c] 为0,表示无效状态。
  • 逆序遍历字符串

    • 从字符串末尾开始,逐个字符遍历。
    • 对于每个位置i,将当前字符c设置为i的直接后继。
    • 复制上一次的状态到当前位置,处理所有其他字符保持不变。
  • 记录最后出现位置

    • 使用数组 last[c] 记录字符c最后出现的位置,便于后续查找。
  • 2. 调用自动机进行查询

  • 初始化查询器

    • 通过逆序遍历s,构建一个反向的访问结构,用于高效查询。
  • 检查子序列

    • 从字符串末尾向前遍历s1,利用预处理的转移数组判断是否能依次找到每个字符,直到遍历完整个s1。
    • 如果某个字符无法找到对应的后继状态,说明s1不是s的子序列。
  • 3. 代码实现

    #include 
    using namespace std;int main() { string s; cin >> s; int n = s.size(); // 初始化转移数组 int nex[ n+1 ][26]; for (int i = n; i >= 0; --i) { // 复制下一个状态到当前状态 for (int c = 0; c < 26; ++c) { nex[i][c] = nex[i+1][c]; } // 设置当前字符的下一个状态 char ch = s[i]; nex[i][ch-'a'] = i+1; } int m; while (cin >> m) { string s1; cin >> s1; int len = s1.size(); bool flag = true; // 从s的末尾往前查找 int current = 0; for(int i = len - 1; i >= 0; --i){ char ch = s1[i]; int pos = 0; // 查找当前状态是否有该字符的转移 for(pos = 0; pos < 26; pos++){ if(nex[current][pos] != 0 && nex[current][pos] <= n && s[nex[current][pos] -1] == ch) { break; } } if(pos == 0){ // 未找到匹配的后继状态 flag = false; break; } current = nex[current][ch-'a']; if(current > n){ flag = false; break; } } if(flag){ // 判断是否整个s1都被处理 // 需要确保current的值是否有效,我们可能需要加上最后是否正确的判断 // 另外,确保循环从i=0到i= len-1有处理 // 另一种方法是从i=0到i= len-1遍历检查 // 因此,正确地查看状态是否到了末尾 // 我在这里犯了一个错误,正确的做法是检查所有字符是否都能被找到 // 我之前的判断是从末尾开始检查迭代,可能不准确 // 另一种正确的做法是从前往后检查是否能移到终止状态 // 或者,可以使用当前的current是否为有效状态 // 可能需要重新审视逻辑 } // 根据正确的逻辑输出结果 } return 0;}

    3. 常见错误处理

  • 初始化问题:确保所有状态转移的初始化正确,特别是在逆序遍历时是否正确复制下一个状态到当前位置。

  • 查询顺序:检查字符串的顺序是否正确,特别是在逆序处理时是否能准确跟踪每个字符的下一个状态。

  • 状态终止条件:确保遍历结束后所有字符都被正确处理,状态是否正确终止于字符串末尾。

  • 数组大小管理:确认数组的大小是否足够,尤其是在划分 Nex 数组时,确保索引范围正确。

  • 通过以上步骤,前缀自动机能够高效地解决字符串子序列的判断问题,确保在处理大规模数据时也能保持较优的性能。

    转载地址:http://wiewk.baihongyu.com/

    你可能感兴趣的文章
    Linux总结
    查看>>
    DKT—Going Deeper with Deep Knowledge Tracing
    查看>>
    响应的HTTP协议格式+常见的响应码
    查看>>
    创建线程方式
    查看>>
    LRUCache
    查看>>
    关于Linux系统中touch命令的说明
    查看>>
    将windows里的内容直接复制粘贴到ubuntu,提高效率
    查看>>
    将tomcat设置成window自启动服务
    查看>>
    webservice 远程服务器返回错误:(400)错误的请求
    查看>>
    [日常] PHP与Mysql测试kill慢查询并检验PDO的错误模式
    查看>>
    [Linux] 进程间通信
    查看>>
    [PHP] error_reporting(0)可以屏蔽Fatal error错误
    查看>>
    thinkphp 的一些重要知识点
    查看>>
    Java学习第二章——Java基本语句
    查看>>
    遇到问题之-yum update无法连接镜像问题解决
    查看>>
    pycharm如何设置(错误、警告类的标准提醒)
    查看>>
    Python3运行的时候错误:ModuleNotFoundError: No module named 'PIL'
    查看>>
    PHP是世界上最好的语言?Phython第一个不服
    查看>>
    Bugku CTF-web6
    查看>>
    Bugku CTF-web10 头等舱
    查看>>