About
我感觉这道题应该是比较经典的题了,甚至有专门解此题的算法,虽然这是一道中等难度的题,但是该题却困扰了我一天(TAT),没办法,菜是原罪,现将解体经过整理如下
求字符串的最长回文子串
题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
解题思路
刚开始解题时采用一贯思路,从头开始遍历字符串,写出来的算法直接超时,后来受评论区提出的中心扩展法
启发,终于有了思路
-
回文字符串
是关于自己中心对称的,所以我们的思路是从子串的中心点去扩展,如果距离中心距离相等的两个点的值相等,那么就继续往下扩展。 - 如果一个字符串的长度为
n
,那么中心点应该有2n-1
个。 - 如果从父字符串的中心开始遍历则时间复杂度最佳情况为O(n),所以我们选择从父字符串的中心往两边遍历中心点
代码如下(Python3)
import math, numpy
class Solution:
def check(self, s: str, index: float) -> bool:
'''
从中心点开始扩散,找到基于该中心点的最长子串
:param s: 父字符串
:param index: 中心点在父字符串的索引
:return: 回文子串
'''
res = ''
Range = int(index) + 1 if int(index) < len(s) - math.ceil(index) else len(s) - math.ceil(index)
for counter in range(Range):
if s[math.floor(index - counter)] == s[math.ceil(index + counter)]:
res = s[math.floor(index - counter): math.ceil(index + counter) + 1]
else:
return res
return res
def longestPalindrome(self, s: str) -> str:
'''
从父串的中心开始遍历
:param s: 输入的父串
:return: 最长回文子串
'''
res, temp = [], []
length = len(s)
if length <= 1:
return s
for index in numpy.arange(0, (length-1)/2, 0.5):
if len(self.check(s, (length-1)/2 - index)) > len(self.check(s, (length-1)/2 + index)):
temp = self.check(s, (length-1)/2 - index)
else:
temp = self.check(s, (length-1)/2 + index)
if len(temp) > len(res):
res = temp
if len(res) >= (length/2 - index) * 2:
return res
return s[0]
运行结果
很明显,算法性能不佳,一部分是语言的原因(Java最快的14ms),当然更多的是我这算法设计的不行
解法2
看了精选题解的算法,动态规划算法最普适,但是时间复杂度太高,性能不及我的算法,性能最好的”马拉车算法“没看懂(TAT),于是又冒出一个新的想法
思路:
上面的写法我感觉还可以改进,比如:从中心一步步扩展,到底还是需要遍历这个字符串,但是如果我们不去比较单个元素,直接比较字符串呢,然后利用二分法快速迭代到不相等的点,然后根据该点的索引对字符串进行切片,简直不要太快,哈哈哈哈哈哈啊哈哈哈。伪代码如图所示:
即先判断
abcd = eecd?
相等了就返回,不相等再判断cd = cd?
如果相等再判断bcd = ecd?
,不相等就返回cddc
,相等就返回bcdecd
。但是,但是!!!由于我太菜了,其中索引值半天算不好,递归也没学好,55555写了两个小时没写出来遂作罢,希望有缘人看到我的想法能帮我实现一下谢谢~~~~~