Manacher算法解决回文字符串问题

302 阅读2分钟

Manacher算法

关键词

字符串、回文、子串、线性复杂度

用途

快速找到一个字符串的最大回文子串

复杂度

时间复杂度:O(N)

空间复杂度:O(N)

中心扩展法

过程

从头到尾遍历字符串,对于每个元素x:

​ 从x开始向左右扩展,直到左右元素不相等或抵达字符串边界

复杂度

时间复杂度:O(N2N^2)

空间复杂度:O(NN)

优化思路

考虑在从前往后遍历x时,前边迭代中的信息有可能对后边的迭代有帮助,因此可以想办法用到这些信息来减少复杂度。

Manacher算法

过程

  • 在从前往后扩展x时,对于每个x,记录下它扩展了多少位,存放在数组d中。则我们只要求出d数组,就等于求出了所有的回文子串。
  • 考虑对于一个回文字符串a,容易知道它是对称的。因此,设a[i],a[j]关于字符串的中心对称,那么a[i]和a[j]能够向左右扩展的位数,应该是一样的。
  • 因此我们在进行中心扩展时,维持一个记录右边界最大的回文子串(通俗的讲,就是前边扩展的时候,把能扩展到最右边的子串给记下来)。
  • 那么在进行后边的扩展时,如果这次的中心不在之前“维护的那个回文子串”里,我们就只能按一般地方法去中心扩展。但是如果它在之前“维护的那个回文子串”里,我们就可以利用第二条的结论,通过它对称位置记录的d,得到它在这个回文子串里的最大回文子串(注意理解,此处比较绕)
  • 理解了上条,你会发现有点不对:我要求的是在整个字符串的最大回文子串,你只给我求出在之前“维护的那个子串”里的子串是怎么回事。
  • 因此我们在进行了上一步的操作后,只需要从“维护的子串”的边界继续向外扩展就可以了。

参考资料

  1. OI Wiki, Manacher算法 [oi-wiki.org/string/mana…]