https://leetcode-cn.com/problems/longest-palindromic-substring/
解法一
采用动态规划的思路来优化暴力解法。
暴力解法自然是找出所有的子串然后判断是否是回文串,子串可以用其开头start和结尾end两个变量来表示。找到所有子串这个过程是没法优化的,因此我们要思考如何优化判断回文串这个过程。
对于dp[start][end]
,必须满足end >= start
(首尾不能颠倒):
- 易知
start == end
时dp[start][end] = true
,即单个字符为回文串 end == start + 1
时,子串只有两个字符,是否为回文串就看这两个字符是否相等end > start + 1
时,子串长度大于2,首先判断首尾两个字符是否相等,然后通过动态规划获取dp[start+1][end-1]
的值,即除掉首尾后是否为回文串。若都满足则该子串为回文串。
需要注意,在采用动态规划时,要获取dp[start+1][end-1]
的值,因此start要从大往小遍历,end要从小往大遍历,并且end >= start
。
代码
class Solution {
public:
string longestPalindrome(string s) {
int n = s.length();
if (n == 0) return "";
bool isPalin[n][n];
string result(1, s[n - 1]);
for (int start = n - 1; start >= 0; --start) {
isPalin[start][start] = true;
for (int end = start + 1; end < n; ++end) {
isPalin[start][end] = s[start] == s[end];
if (end > start + 1) isPalin[start][end] = isPalin[start][end] && isPalin[start + 1][end - 1];
if (isPalin[start][end] && end - start + 1 > result.length())
result = s.substr(start, end - start + 1);
}
}
return result;
}
};
复杂度分析
算法要找到所有的start和end,这个过程时间复杂度
O
(
n
2
)
O(n^2)
O(n2),利用动态规划来判断s[start~end]是否为回文串,时间复杂度为
O
(
1
)
O(1)
O(1),因此总的时间复杂度
O
(
n
2
)
O(n^2)
O(n2)。空间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
需要注意,要用原生数组而不是vector
来存储isPalin
,因为vector
的效率比原生数组要低很多,上述代码若改成vector
则会超时。
解法二
中心扩散算法
考虑一个已经为回文串的子串,如果我们继续以它为中心去寻找回文串的话,自然是向左右两边扩散,如果两边字符相等则回文串增长,否则停止扩散。中心子串长度可能为1,也可能为2,需要全部考虑进去。
我们对所有可能的中心子串做中心扩散算法,找到以它们为中心的最长回文子串。
代码
class Solution {
public:
string longestPalindrome(string s) {
int start = 0, end = 0;
for (int i = 0; i < s.length(); ++i) {
auto [left1, right1] = expandStr(s, i, i);
auto [left2, right2] = expandStr(s, i, i + 1);
if (right1 - left1 > end - start) {
start = left1;
end = right1;
}
if (right2 - left2 > end - start) {
start = left2;
end = right2;
}
}
return s.substr(start, end - start + 1);
}
private:
pair<int, int> expandStr(string s, int left, int right) {
while (left >= 0 && right < s.length() && s[left] == s[right]) {
left--;
right++;
}
return {left + 1, right - 1};
}
};
复杂度分析
遍历中心子串复杂度 O ( n ) O(n) O(n),扩散算法复杂度 O ( n ) O(n) O(n),总的时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1)。