LeetCode: 最长回文子串
题目:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
初步尝试:暴力解法
基本思路:
- 全部循环得到所有可能的回文子串并储存。
- 判断最长的回文后输出
这道题我完全不知道怎么下手,参考原文地址
class Solution:
def longestPalindrome(self, s):
# 如果字符串长度为1,直接返回原字符串
len_s = len(s)
if len_s == 1:
return s
# 新建空的字符串保存回文,新建一个空的列表保存所有可能的回文子串
substring = ''
substring_set = []
for i in range(len_s):
for j in range(len_s):
if i < j:
substring = s[i:j+1]
if self.is_Palindrome(substring) == 1:
substring_set.append(substring)
longestP = ''
if substring_set:
longestP = substring_set[0]
else:
return s[0]
# 判断最长回文子串
for i in range(len(substring_set)):
if len(longestP) < len(substring_set[i]):
longestP = substring_set[i]
return longestP
# 判断是否为回文字串
def is_Palindrome(self, t):
len_t = len(t)
for i in range(len_t):
if not t[i] == t[len_t - 1 - i]:
return 0
return 1
s = Solution()
s.longestPalindrome('babad')
这样做的缺点很明显,就是会浪费很多的时间。
思路二:“马拉车”算法 Manacher’s Algorithm
- 插入 #,使得字符串变为奇数
- 寻找回文最大右半径
举个例子:s=“abbahopxpo”,转换为s_new="$#a#b#b#a#h#o#p#x#p#o#"
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s_new[i] | $ | # | a | # | b | # | b | # | a | # | h | # | o | # | p | # | x | # | p | # | o | # |
p[i] | 1 | 2 | 1 | 4 | 5 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 6 | 1 | 2 | 1 | 2 | 1 |
原文地址:https://blog.csdn.net/qq_39241986/article/details/82927399
这个对于我来讲还是太难了
class Solution:
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
t0 = '#'.join(s)
s_new = '#' + t0 + '#'
len_new = []
sub = '' # 最长回文字符串
sub_midd = 0 # 表示在i之前所得到的Len数组中的最大值所在位置
sub_side = 0 # 表示以sub_midd为中心的最长回文子串的最右端在S_new中的位置
for i in range(len(s_new)):
if i < sub_side :
# i < sub_side时,在Len[j]和sub_side - i中取最小值,省去了j的判断
j = 2 * sub_midd - i
if j >= 2 * sub_midd - sub_side and len_new[j] <= sub_side - i:
len_new.append(len_new[j])
else:
len_new.append(sub_side - i + 1)
else:
# i >= sub_side时,从头开始匹配
len_new.append(1)
while ((i - len_new[i] >= 0 and i + len_new[i] < len(s_new)) and (s_new[i - len_new[i]] == s_new[i + len_new[i]])):
# s_new[i]两端开始扩展匹配,直到匹配失败时停止
len_new[i] = len_new[i] + 1
if len_new[i] >= len_new[sub_midd]:
sub_side = len_new[i] + i - 1
sub_midd = i
a0 = int((2 * sub_midd - sub_side)/2)
b0 = int(sub_side / 2)
sub = s[a0 :b0 ] # 在s中找到最长回文子串的位置
return sub
还有一个办法是从中间入手,向两边拓展,分奇偶讨论,这里就不放出来了。