zoukankan      html  css  js  c++  java
  • 最长子回文字符串(Manacher’s Algorithm)

    # # 大佬博客:
    https://www.cnblogs.com/z360/p/6375514.html
    https://blog.csdn.net/zuanfengxiao/article/details/80341483
    多个方法:https://blog.csdn.net/asd136912/article/details/78987624
    

    自己的总结

    # Manacher’s Algorithm, 复杂度o(n)
    # 有两个主要的步骤:
    # 将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。abba => #a#b#b#a#, aba => #a#b#a#
    # 用数组 len_str[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度,并增加两个辅助变量po和maxr,
    # 其中 po 为已知的 {右边界最大} 的回文子串的中心,maxr则为po+len_str[po],也就是这个子串的右边界。
    class Solution(object):
        def longestPalindrome(self, s):
            """
            :type s: str
            :rtype: str
            """
            # 转换字符串s,开头和结尾都添加一个特殊符号防止数组越界
            s = "#" + "#".join(s) + "#"
            # max_length 为转换后的字符串s中以某一个字符为中心的子回文字符串的最大长度,
            max_length = 0
            # maxr为当前计算回文串最右边字符的最大值(以po为中心的子回文字符串的最右边的点)
            maxr = 0
            # 设maxr为之前计算中最长回文子串的右端点的最大值,并且设取得这个最大值的位置为po(po为取得maxr的中心点)
            po = 0
            # 转换之后的s中, 以任意一个字符i为中心的子回文字符串的长度都是奇数(2*len_str(i)-1),
            # 而以任意一个字符为中心的子回文字符串中, 添加的特殊符号"#"的个数为len_str(i)个, 所以剩下的原字符串中的字符个数为len_str(i)-1,
            # 所以关键问题就是求len_str(i)的值, len_str(i)表示在转换之后的字符串s中以i为中心的子回文字符串的长度
            len_str = [0]*len(s)
            # 求len_str(i)分两种情况:
            # 1. maxr > i, 假设找到i关于po的对称位置并设为j, 假设len_str(j) < maxr - i, 说明以j为中心的子回文字符串是在以po为中心的子回文字符串中包含的
            # 由回文串的定义可知,一个回文串反过来还是一个回文串,所以以i为中心的回文串的长度至少和以j为中心的回文串一样,
            # 即len_str[i]>=len_str[j](以i为中心的子回文字符串的长度可能比以j为中心的子回文字符串的长度大, 但至少是和j一样),
            # 因为len_str[j]<maxr-i,所以说i+len_str[j]< maxr。由对称性可知len_str[i] = len_str[j], 所以当maxr>i时, 取len_str[i]的条件是
            # len_str[j] < maxr -i, 即len_str[i] = min(maxr-i, len_str[2*po-i]), i和j是关于po对称的, j = 2*po-i
            # 2. maxr <= i, maxr为已知的取得最长回文子串的右端点的最大值, 如果maxr<=i, 则以i为中心的子回文字符串还未匹配, 所以初始化为1(它自己),
            # 匹配完成后要更新maxr的位置和对应的po以及len_str[i]
    
            # 关键点: 求以i为中心的子回文字符串的长度len_str[i]
            for i in range(len(s)):
                if maxr > i:
                    len_str[i] = min(maxr - i, len_str[2*po-i])
                else:
                    len_str[i] = 1
                # 要保证数组不能越界
                while i-len_str[i] >= 0 and i+len_str[i] < len(s) and s[i-len_str[i]] == s[i+len_str[i]]:
                    len_str[i] += 1
                # 如果匹配到更长的子回文字符串, 则进行更新
                if len_str[i] + i > maxr:
                    maxr = len_str[i] + i
                    po = i
                # max_length - 1即为原字符串中最长的回文子字符串的长度
                max_length = max(max_length, len_str[i])
            # len_str.index(max_length)即为取得最长子回文字符串的点i的位置, 而在该点取得的子回文字符串长度为2*max_length-1(为奇数),
            # max_length-1表示左边和右边对称的长度(不包含中心点), 2*max_length-1 = max_length-1 + 1 + max_length-1
            # 所以len_str.index(max_length) - (max_length - 1)为左端点,len_str.index(max_length) + (max_length - 1)为右端点
            s = s[len_str.index(max_length) - (max_length-1):len_str.index(max_length) + (max_length-1)]
            s = s.replace('#', '')
            return s
    
    so = Solution()
    print so.longestPalindrome("aabbccbbaa")
    
    
    
  • 相关阅读:
    12 KLT算法
    1- js vue.js
    复用代码
    计算两个日期相隔的天数(jodd)
    [转]ORA-00907: 缺失右括号
    [转]sql server 数据库日期格式化函数
    [Oralce]Oralce格式化日期
    myeclipse内存配置
    cookie 编码问题
    [转]Oracle 操作字符串的函数
  • 原文地址:https://www.cnblogs.com/nyist-xsk/p/10419177.html
Copyright © 2011-2022 走看看