题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: “aba” 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
思路一
常见错误
有些人会忍不住提出一个快速的解决方案,不幸的是,这个解决方案有缺陷(但是可以很容易地纠正):
反转S,使之变成S′。找到S 和S′ 之间最长的公共子串,这也必然是最长的回文子串。
这似乎是可行的,让我们看看下面的一些例子。
例如,S = “caba”, S' = “abac”;
S 以及S′之间的最长公共子串为“aba”,恰恰是答案。
尝试一下这个例子:S= “abacdfgdcaba”,
S' = “abacdgfdcaba”;
S 以及 S′之间的最长公共子串为 “abacd”,显然,这不是回文。
当 SS 的其他部分中存在非回文子串的反向副本时,最长公共子串法就会失败。为了纠正这一点,每当我们找到最长的公共子串的候选项时,都需要检查子串的索引是否与反向子串的原始索引相同。如果相同,那么我们尝试更新目前为止找到的最长回文子串;如果不是,我们就跳过这个候选项并继续寻找下一个候选。
这给我们提供了一个复杂度为 O(n^2) 动态规划解法,它将占用 O(n^2)的空间(可以改进为使用 O(n) 的空间)。
思路二 (动态规划)
为了改进暴力法,我们首先观察如何避免在验证回文时进行不必要的重复计算。考虑“ababa”
这个示例。如果我们已经知道“bab”
是回文,那么很明显,“ababa”
一定是回文,因为它的左首字母和右尾字母是相同的。
我们给出 P(i,j)P(i,j) 的定义如下:
如果子串是回文子串其他情况
$$f(i,j)=
\begin{cases}
true& \text{如果子串Si…Sj是回文子串}\
false& \text{其他情况}
\end{cases}$$
因此,1
P(i,j) = (P(i+1,j-1) and S_i==S_j)
基本示例如下:1
2P(i,j) = true;
P(i,i+1) = (S_i == S_i+_1)
这产生了一个直观的动态规划解法,我们首先初始化一字母和二字母的回文,然后找到所有三字母回文,并依此类推…
复杂度分析
时间复杂度:O(n^2)
,这里给出我们的运行时间复杂度为 O(n^2)
。
空间复杂度:O(n^2)
,该方法使用O(n^2)
的空间来存储表。
具体代码
1 | class Solution { |