博客
关于我
月月查华华的手机(每日一题)序列自动机
阅读量: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/

    你可能感兴趣的文章
    增量收集算法、分区算法
    查看>>
    密码学的基本概念
    查看>>
    JavaScript内置对象
    查看>>
    数据库和SQL 概述
    查看>>
    MySQL常见函数
    查看>>
    算法:从有序数组中移除重复的数据26. Remove Duplicates from Sorted Array
    查看>>
    springboot整合ehcache+redis实现双缓存
    查看>>
    wxPython4.0.4关于我们
    查看>>
    关于小程序去除view/navigator 点击后默认阴影效果
    查看>>
    js数组去重的多种方法
    查看>>
    高德打车构建可观测性系统实践
    查看>>
    rust实践 - 简易的单线程web服务器(一)
    查看>>
    计算机专业导论——语言与算法 (思维导图)
    查看>>
    java home path catia_JAVA环境变量JAVA_HOME、CLASSPATH、PATH设置详解
    查看>>
    通俗易懂的JDK1.8中HashMap源码分析(欢迎探讨指正)+ 典型面试题
    查看>>
    VMware虚拟机提示“以独占方式锁定此配置文件失败解决方案
    查看>>
    HDU 1016 Prime Ring Problem 素数环【DFS】
    查看>>