• 字符串的最长回文串:Manacher’s Algorithm


    题目链接:Longest Palindromic Substring

    1. 问题描述

    Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

    2. 各种解法复杂度

    • 暴力枚举:O(N^2)
    • 记忆化搜索:O(N^2)
    • 动态规划:O(N^2)
    • Manacher’s Algorithm : O(N)

    3. Manacher’s Algorithm

    步骤:

    1. 字符串里相邻两个字符之间插入一个 # ,开头和结尾也加上 # 。
      例如:
      Str = “abaaba”, Trans = “#a#b#a#a#b#a#”.
      注:Trans 为 transform

    2. 声明一个数组 P[n] : 其中 n 为 Trans 的长度。P[index] 表示以 index 为中心的最长回文串长度(不包括 index 本身)。例如:

      Trans = # a # b # a # a # b # a #
          P = 0 1 0 3 0 1 6 1 0 3 0 1 0
      

      声明变量 Cur :表示当前回文串最长的中心的下标(current position),初值为0。
      声明变量 Right : 表示以Cur为中心的回文串最右一个字符所处位置。

    3. 建立循环,以增量 index 为中心,扩展 index 。也就是检查 index 两边是否相等。如果相等, P[index] 加1。

      在循环体中:

      • 变量 index :
        当前检查的元素的下标。
      • 声明变量 index_ mirror
        以Cur为对称轴, index 的对称位置,index_mirror = Cur - ( index - Cur )
      • 在扩展之前检查 Right 是否大于 index :
        如果是,那么 P[index] 的值直接赋值为 min(R - index, P[index_mirror]) ;否则P[index] = 0。
    4. 如果 index + P[index] > Right ,将 Cur 更新为 index 。

    5. 找出 P[] 的最大值即是答案。

    4. Q&A

    • 为什么要插入 # ?
      比如 abba ,以第一个 b 的下标为 index ,如果要比较 index 的回文,那么它就得比较 index 和 index+1
      如果插入 #a#b#b#a# ,第一个 b 后面的 # 下标为 index ,则比较 index - 1 和 index + 1 这样代码更清晰,也更好理解。此时 # 的 P[] 值就表示该位置的回文串长度。

    • 其他

      如上图。由于我们已经检查出 Cur 位置的回文串长度是 9 ,那么 Cur 左右两边的 9 个字符是对称的。如果 index_mirror 的 P[] 值小于等于 R-index 的值(即距离),那么令 P[index] = P[index_mirror] ——对称的性质。为什么要小于他们的距离?因为如果大于他们的距离,例如图中最左边的 a ,它回文串的范围超出了 Cur 回文串的范围,超出 Cur 范围的对称性是未知的。从图中我们可以看出,在对称右边的 a 显然 P[] 值跟左边的不相等,它是 1 。此时只能以 index 为中心继续比较(而不是直接令 P[index] = P[index_mirror] ,因为对称性质无法使用)。

      在检测 index 的最大回文串时,如果检测到 index 的回文串长度最右侧大于 Cur 的最右侧,也就是 Right ,那么将 Cur 更新为 index 。因为如果后面的元素本来可以用更新前 Cur 的对称性,那么更新后的 Cur 的对称性它同样可以用。而 Cur 的更新会使得更后面的元素可以用其对称性。

    参考链接:

    1. Longest Palindromic Substring Part II
    2. Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
    3. soulmachine/leetcode -- Github
  • 相关阅读:
    iOS 代码让手机震动一下
    iOS开发 --制作圆形的头像(UIImage)
    JAVA基本数据类型和引用数据类型的区别
    jquery基础
    JS基础
    JAVA异常详解
    单例模式详解及java常用类
    JAVA基础之字符串和面向对象
    我的第一篇博客 初识动画,飞机行小动画
    GCD系列:调度组(dispatch_group)
  • 原文地址:https://www.cnblogs.com/schaepher/p/6543605.html
Copyright © 2020-2023  润新知