Leetcode-最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
1. 方法一:暴力查找
直接循环字符串,判断子串是否是回文子串,然后得到最长回文子串;这里用到了字符串方法rfind,也可以直接取当前子字符串直接判断
class Solution:
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
len_str = len(s)
if len_str <= 1: #如果输入字符串长度小于等于1,返回字符串本身
return s
max_str = ""
for i in range(len_str):
for j in range(len_str, i, -1):
temp = s.rfind(s[i],i+1,j) #从右往左找第一个s[i],返回序号
if temp != -1:
new_str1 = s[i:(temp+1)]
new_str2 = new_str1[::-1] #[::-1]将数组倒序储存
if (new_str1 == new_str2) and (len(new_str1)>len(max_str)): #判断是否相等且当前子字符串是不是最大
max_str = new_str1
if max_str != "": #如果没找到max_str,就返回第一个字符串
return max_str
else:
return s[0]
- 此方法时间复杂度应该是O(n3),超级慢
2. 方法二:中心扩展
遍历字符串,然后判断字符串前后两个字符串是否相等,以此类推。该方法需要根据输入的字符串的奇偶性分别进行查找,为了方便,可以将原字符串间加入“#”,这样只需要遍历一次即可。
class Solution:
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
len_str = len(s)
if len_str <= 1:
return s #如果输入字符串为空或者只有一个,则返回字符串
max_len = 0
start_res = 0
new_str = "#" + "#".join(s) + "#" #如将字符串“abbc”变为"#a#b#b#c#"
new_len = len(new_str)
for i in range(new_len):
j = i - 1
k = i + 1
while j >= 0 and k < new_len and new_str[j] == new_str[k]:
if k - j + 1 > max_len:
max_len = k - j + 1
start_res = j
j -= 1
k += 1
if max_len>1:
return new_str[start_res:start_res + max_len].replace("#",'') #字符串replace方法,替换原字符串某字符为指定字符
return s[0]
- 该方法时间复杂度为O(n2)
3.Manacher(马拉车)算法
https://mp.weixin.qq.com/s/RQ_gW8kqLun4_X-kpkqzxg 分享一个非常有意思的马拉车算法解释。
还有这个,https://segmentfault.com/a/1190000003914228
- 将原字符串间插入特殊的符号,如方法二
- 定义一个数组arr记录每个字符的回文半径
- 遍历字符串,求取每个字符串i位置数组对应的回文半径arr[i](如"1536348"6对应的半径为1)。定义一个变量rmax和rpos分别表示当前找到的最右边的回文序号和对应的位置。不断更新rmax和rpos。
class Solution:
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
len_str = len(s)
if len_str <= 1:
return s #如果输入字符串为空或者只有一个,则返回字符串
new_str = "#" + "#".join(s) + "#" #如将字符串“abbc”变为"#a#b#b#c#"
new_len = len(new_str)
arr_str = [0] * new_len #定义一个等长的数组记录每个字符的回文字符个数
rpos = 0 #rpos为当前遍历下找到的最右边字符对应的回文对称轴
rmax = 0 #rmax为当前遍历下找到的最右边字符对应的序号
max_pos = 0 #记录最大回文对称轴位置
max_rad = 0 #记录最大回文对称半径
for i in range(new_len):
if i < rmax:
arr_str[i] = min(arr_str[2 * rpos - i], rmax - i) #取当前i的对称位置的arr_str,但有右边越界风险,所以跟rmax - i取最小
else:
arr_str[i] = 0
while i - arr_str[i] -1 >= 0 and i + arr_str[i]+1 < new_len \
and new_str[i - arr_str[i]-1] == new_str[i + arr_str[i]+1]: #找当前i下是否还有其余的回文字符
arr_str[i] += 1
if i + arr_str[i] > rmax: #更新rmax、rpos
rmax = i + arr_str[i]
rpos = i
if(arr_str[i] > max_rad): #更新max_rad、max_pos
max_rad = arr_str[i]
max_pos = i
return new_str[max_pos-max_rad:max_pos+max_rad+1].replace("#",'')
- 此方法的时间复杂度O(n)