算法:最长回文字串

求最长回文字符串是面试中的一道经典题目!给定一个字符串s,从中找出最长的回文字符串:

比如:

s = "fggfsrtrsa"

返回 "srtrs"

解题思路:

其实最简单的可以用动态规划,时间复杂度为O(n^2),这种解法就不加赘述了。我这里会介绍时间复杂度为O(n)的算法:

Manacher算法:

  • 首先用特定字符,比如"#",去填充原来的字符串s:

s = [f,g,g,f,s,r,t,r,s,a]

s=[\#,f,\#,g,\#,g,\#,f,\#,s,\#,r,\#,t,\#,r,\#,s,\#,a,\#]

这样做的一个好处是:无论原字符串长度是奇是偶,都能变成奇数长度2*len(s)+1:

[a]\quad->\quad[\#,a,\#]

[a,a]\quad->\quad[\#,a,\#,a,\#]

 

  • 用Len数组去储存s中以每个位置为中心所能形成的最长回文字符串的边长:

比如 Len[4]=5,因为 [\underline{\#,f,\#,g,{\color{Red} \#},g,\#,f,\#},s,\#,r,\#,t,\#,r,\#,s,\#,a,\#]

比如 Len[5]=2,因为 [\#,f,\#,g,\underline{\#,{\color{Red} g},\#},f,\#,s,\#,r,\#,t,\#,r,\#,s,\#,a,\#]

所以 Len[i]=[1,2,1,2,5,2,1,2,1,2,1,2,1,6,1,2,1,2,1,2,1]

显而易见,最长回文字串的长度就是max(Len)-1!最长回文字串的中点就在max(Len)所在位置!

从这里就能看出添加“#”的另一个好处:

无论什么情况,一个回文字串都可以以“从中心点发散”的形式表示,这样就能对应到s中的每个点!

不添加“#”,在遇到偶数回文串的时候就没法从中心点发散,比如 [2,6,6,2]

 

  • 最后只需要从中心点截取前后max(Len)-1长度,再去掉“#”:

上述的例子,最后截取出来为 [\#,s,\#,r,\#,t,\#,r,\#,s,\#]

 

具体代码(Python3):

    def longestPalindrome(self, s):
        '''
        :param s: str
        :return: str
        '''
        s = list(s) #将str变为list
        Len = []
        length = len(s)
        for i in range(0, 2*length+1, 2): #在偶数位插入符号
            s.insert(i,'#')
        for i in range(len(s)):
            n = 1
            try:
                while s[i-n] == s[i+n]:
                    n += 1
            except IndexError:
                pass
            Len.append(n)
        max_len = max(Len)
        location = Len.index(max_len) #最长的Len在s列表中的位置
        palindrome = s[location - max_len + 1: location + max_len - 1]
        while '#' in palindrome:
            palindrome.remove('#')
        return ''.join(palindrome) #list变为str

猜你喜欢

转载自blog.csdn.net/qq_38310176/article/details/81068750