算法浅谈——字符串相关

个人水平所限,只能谈及几年前的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

posted on 2016-03-22 10:33  IceDream61  阅读(972)  评论(0编辑  收藏  举报

导航