给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba”也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
题意分析:
经典题型,找字符串中最长的回文子串(substring),子串的定义是要求必须连续的,和子序列(subsequence)是两个不同的东西!
思路分析:
在我的多篇博客里始终强调,我们解题一定要看数据范围,leetcode上很多题并不会给出数据范围,这其实特别不好,数据的大小完全决定了我们是否可以采取高复杂度的方法。
这道题s长度不超过1000,显然是在暗示我们O(n^2)的方法是可行的。
一句题外话:通常这类最长子串,最长子序列问题都是可以用dp来求解的,并且他们的dp定义大多类似,一般为dp[i][j]代表在s[i:j+1]中的所求结果
,显然dp[0][n]即为最后所求。
这道题也是一样,我们定义dp[i][j]代表s[i:j+1]中最长回文子串的长度
,那么dp[0][n]即为所求!
递推式分析:
那么dp[i][j]
如何变化呢,因为子串要求连续,如果s[i] != s[j]
,显然dp[i][j] = 0
;
如果s[i] == s[j]
,我们需要知道中间部分是否也是回文子串,若是,dp[i][j] = 2 + dp[i+1][j-1]
,若不是,则dp[i][j] = 0
初始状态分析:
显然dp[i][i] = 1
由于dp[i][j] = 2 + dp[i+1][j-1]
需要满足j-1 >= i+1
, 即j-i >= 2
,所以j == i+1这种情况要单独处理!
注意这道题实际要求的并不是长度,而是字符串,所以我们使用dp
来记录长度,用另一个变量cnt
,来记录下标i,j
,最后返回s[i:j+1]
即可
1 | # 2964ms, beats 26.39% |
你可能会好奇为什么这个算法只beats这么点人。那是因为单从这道题的数据来说,还有着更优的解法。
也就是依次遍历s中的每一个字符ss,以ss作为回文串的中点向两边扩展,然后记录长度!
但是我个人更偏向于第一种解法(dp),因为这才是这类型题的标准解法,不过实际我第一次做的时候也是采用的这种遍历的方法。这里给出代码如下:
1 | class Solution(object): |
其实还有更优的解法,但是太累了,不想写了!