求最长回文字符串是面试中的一道经典题目!给定一个字符串s,从中找出最长的回文字符串:
比如:
s = "fggfsrtrsa"
返回 "srtrs"
解题思路:
其实最简单的可以用动态规划,时间复杂度为O(n^2),这种解法就不加赘述了。我这里会介绍时间复杂度为O(n)的算法:
Manacher算法:
-
首先用特定字符,比如"#",去填充原来的字符串s:
这样做的一个好处是:无论原字符串长度是奇是偶,都能变成奇数长度2*len(s)+1:
-
用Len数组去储存s中以每个位置为中心所能形成的最长回文字符串的边长:
比如 ,因为
比如 ,因为
所以
显而易见,最长回文字串的长度就是max(Len)-1!最长回文字串的中点就在max(Len)所在位置!
从这里就能看出添加“#”的另一个好处:
无论什么情况,一个回文字串都可以以“从中心点发散”的形式表示,这样就能对应到s中的每个点!
不添加“#”,在遇到偶数回文串的时候就没法从中心点发散,比如 。
-
最后只需要从中心点截取前后max(Len)-1长度,再去掉“#”:
上述的例子,最后截取出来为 。
具体代码(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