• 算法浅谈——字符串相关


    个人水平所限,只能谈及几年前的OI省选水平的算法。再高深的,便不清楚了。


    主要参考文献:

    1. hzwer,《OI省选算法汇总》
    2. _Rayx,《多种字符串匹配算法杂谈》
    3. airfer,《字符串匹配算法比较》
    4. 罗穗骞,《后缀数组——处理字符串的有力工具》
    5. xiazdong,《Dijkstra、Bellman_Ford、SPFA、Floyd算法复杂度比较》
    6. Create Chen,《理解A*寻路算法具体过程》
    7. lufy,《A*寻路算法与它的速度》
    8. Amit,蔡鸿译,《Amit's A star Page中译文》

    OI算法,大抵可分为以下几类:

    1. 数据结构
    2. 字符串相关
    3. 图论相关
    4. 数学相关
    5. 动态规划
    6. 计算几何
    7. 不保证正确性的算法
    8. 其他重要工具与方法

    下面依次谈一谈。

    这个算法是怎么来的,是为了解决什么问题而来,以前的算法为什么没有解决,而现在的算法却能解决;现在这个算法还有些什么缺点;能做一些什么问题,不能做些什么问题。—— Ronghua Li

    字符串相关

    单模式串匹配

    • KMP:在主串S(长度N)中匹配一个模式串P(长度M),预处理时间 O(M) ,匹配时间 O(N+M) 。

    • KMP及相关算法时间复杂度比较:

      其中,M为模式串长度,N为主串长度。
      实测时,string长度10000,每个函数都被调用了1000次。
    算法预处理时间匹配时间实测时间
    BF O(0) O(NM) 0.078
    KMP O(M) O(N) 0.094
    BM O(N+M2) O(N) 0.047
    Sunday O(M) O(NM) 0.172
    Robin-Karp O(0) O(NM) 0.328
    Bitap O(M) O(NM)O(N) 0.281

    字典树(Trie)

    Trie是一种n叉树,n为字母表大小,每个节点表示从根节点到此节点所经过的所有字符组成的字符串。

    多模式串匹配

    • AC自动机:在主串S(长度N)中匹配多个模式串P(长度M),预处理时间 O(N+Mi) ,匹配时间 O(N+Mi) 。

    AC自动机就是KMP思想。但用KMP做多模式串匹配的时间复杂度是 O(N+Mi) 。显然,提高的复杂度是 O(N(K1)) ,其中K表示模式串的个数。而当模式串数量大、模式串较短、主串较长时,算法几乎是从 O(N2) 降到了 O(N) 。

    还有一种多模式的匹配算法叫做AC自动机。它能一次匹配多个模式串。它与KMP的思路很像,不匹配时找一个最长的再继续进行!它需要先把字符串建成一颗Trie树,树结点有一个叫做failed的指针,是表示如果不匹配时应该再从哪个结点进行匹配。因为这种做法是一种DFA上的匹配,而发明这种算法的人叫A.C.,所以就叫AC自动机了。复杂度很好,比每个模式串用一次KMP算法要好很多。

    后缀树、后缀数组

    • 这俩是非常有用的字符串处理工具,尤其是后缀数组,很多复杂字符串问题都可以用它来快速完美解决。
    • 构造:倍增算法 O(logN) ,DC3算法 O(N) ,但前者常数小一些,且实现较容易。
    • 内容: 后缀数组与名次数组
      • 后缀数组,SA[1~N],表示“排第几的是谁?”。也就是将S的N个后缀升序排序,把排好序的后缀的开头位置顺次放入SA中。显然,其满足:
        Suffix(SA[i])<Suffix(SA[i+1])
      • 名次数组,Rank[1~N],表示“你排第几?”。也就是 Suffix(i) 在所有后缀中升序排序的名次。
    • 用途:
      • 最长公共前缀
      • 单个字符串的相关问题
        • 重复子串
          • 可重叠最长重复子串
          • 不可重叠最长重复子串 (pku1743)
          • 可重叠的最长重复子串 (pku3261)
        • 子串的个数
          • 不相同的子串的个数 (spoj694, spoj705)
        • 回文子串
          • 最长回文子串 (ural1297)
        • 连续重复子串
          • 连续重复子串 (pku2406)
          • 重复次数最多的连续重复子串 (spoj687, pku3693)
      • 两个字符串的相关问题
        • 公共子串
          • 最长公共子串 (pku2774, ural1517)
        • 子串的个数
          • 长度不小于k的公共子串的个数 (pku3415)
      • 多个字符串的相关问题
        • 不小于k个字符串中的最长子串 (pku3294)
        • 每个字符串至少出现两次且不重叠的最长子串 (spoj220)
        • 出现或反转后出现在每个字符串中的最长子串(pku3294)

    还有一种叫做后缀数组和后缀树的,后缀树是可以转发为后缀数组的,这两种构造起来很不简单,但是复杂度却是惊人的好。如求最长重复连续子串,出现次数最多的子串等都能用它完美的解决。有兴趣的可以搜搜,后缀数组的资料应该是比较多的,而后缀树由于太复杂,资料不是很多,还是有的。

    关于后缀数组构造的倍增算法,有一个特别好玩的小故事,大家可以去看看~

    《后缀树,后缀数组,离散化》,去看73到81页,可爱的小白兔们^_^

    模糊匹配

    上面介绍的都是精确匹配的算法,其实对于字符串,还有一种模糊匹配,有兴趣的读者可以阅读一本叫做《柔性字符串匹配》的书,肯定会让你获益匪浅。

    其他

    • 后缀自动机
    • Manacher
  • 相关阅读:
    学习日记-- 动态性。动态编译,静态方法,包装类
    第一周学习所获———ORM,数据持久化,通过注解来实现数据持久化框架
    第一周学习所获--class类1(反射和类加载过程)
    各种命名规范
    用easyui,json,纯mvc实现一个系统的数据流动过程
    js+bootstrap实现分页页码
    Echarts简单案例
    bootstrap日期控件(双日期、清空等问题解决)
    三种方法实现调用Restful接口
    Spring MVC异常处理 和 重定向传递数据
  • 原文地址:https://www.cnblogs.com/icedream61/p/5305124.html
Copyright © 2020-2023  润新知