题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
根据题意,回文子串:逆序后与原子串一致
思路上首先需要判断是否为回文子串,测试示例只给出最简单的情况——回文时相同字母两次重复,在回文子串中,可能出现字母的多次重复,造成了题目的难度。
联想:寻找无重复字符的最长子串,滑动窗口的思想是从每个字符作为子串起始字符,直到两指针中的右指针到达字符串最后一位。
方法一
类似于之前的做题经验方法,于是采用双指针的思想:
- 左指针控制起始字符的位置;
- 右指针不断向后移动;
- 我们需要做的是在滑动过程中判断最长子串;
由于最后返回的结果是最长子串情况,为降低空间复杂度,将每一次比较后的最优结果(最长回文子串)保存在结果字符串中,直到循环结束,结果字符串即为所求。
- 时间复杂度 O(N2)
当字符串仅包含同一种字符,for 和 while 嵌套,最长为 O(N2) - 空间复杂度O(N)
子串长度最大为原字符串长度 N
耗时长,进一步思考回文子串情况,以某种字符为起始,并且以同种字符为终止,既包含偶数情况,又包含奇数情况。
学习新的算法
中心扩展算法
方法一与动态规划方法类似,中心扩展算法由动态规划方法引申,得到状态转移时可能性是一致的发现,于是从每一种边界情况扩展进而找到所有状态对应的答案。
-
时间复杂度:O(N2)
其中 N 是字符串的长度。长度为 1 和 2 的回文中心分别有 N 和 N - 1 个,每个回文中心最多会向外扩展 O(N) 次。 -
空间复杂度:O(1)。
提交代码
方法一
class Solution:
def longestPalindrome(self, s: str) -> str:
if len(s) == 1:
return s
a = ""
res = ""
length = 0
right = 0
for i in range(len(s)):
a += s[i]
right = i + 1
while right < len(s):
a += s[right]
if s[right] == s[i]:
if a[::-1] == a:
length = max(length,len(a))
if length == len(a):
res = a
right += 1
a = ""
if not res:
return s[0]
else:return res
结果 :超出时间限制
中心扩展算法
class Solution:
def expandAroundCenter(self, s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return left + 1, right - 1
def longestPalindrome(self, s: str) -> str:
start, end = 0, 0
for i in range(len(s)):
left1, right1 = self.expandAroundCenter(s, i, i)
left2, right2 = self.expandAroundCenter(s, i, i + 1)
if right1 - left1 > end - start:
start, end = left1, right1
if right2 - left2 > end - start:
start, end = left2, right2
return s[start: end + 1]
#https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
总结
- 中心扩展算法
与动态规划思想相关,联想理解更有帮助。 - Manacher 算法
在字符串的首尾、相邻的字符中插入分隔符 “#”,新字符串中的任意一个回文子串在原始字符串中的一定能找到唯一的一个回文子串与之对应,新字符串的回文子串的长度一定是奇数;辅助数组 p 记录了新字符串中以每个字符为中心的回文子串的信息。还未作深入了解。