#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
if (n < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i..j] 是否是回文串
vector<vector<int>> dp(n, vector<int>(n));
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= n; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < n; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= n) {
break;
}
if (s[i] != s[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLen);
}
};
初始化变量:
int n = s.size();
:获取字符串s
的长度。if (n < 2) { return s; }
:如果字符串长度小于2,直接返回字符串,因为它本身就是回文串。int maxLen = 1;
:初始化最长回文子串的长度为1,因为任何字符串都有一个长度为1的回文子串(即它本身)。int begin = 0;
:初始化最长回文子串的起始位置。vector<vector<int>> dp(n, vector<int>(n));
:创建一个二维向量dp
,用于存储子串是否为回文的信息,dp[i][j]
表示子串s[i..j]
是否为回文串。初始化动态规划数组:
for (int i = 0; i < n; i++) { dp[i][i] = true; }
:所有长度为1的子串都是回文串,因此初始化对角线为true
。动态规划过程:
for (int L = 2; L <= n; L++) { ... }
:外层循环枚举子串的长度L
,从2开始,因为长度为1的最长回文子串已经初始化。for (int i = 0; i < n; i++) { ... }
:内层循环枚举子串的左边界i
。int j = L + i - 1;
:根据左边界i
和长度L
计算右边界j
。if (j >= n) { break; }
:如果右边界越界,退出当前循环。判断回文并更新最长回文子串:
if (s[i] != s[j]) { dp[i][j] = false; } else { ... }
:如果左右边界字符不同,则s[i..j]
不是回文串;否则,需要进一步判断。if (j - i < 3) { dp[i][j] = true; } else { dp[i][j] = dp[i + 1][j - 1]; }
:如果子串长度小于4,则只需要判断左右边界字符是否相同;如果长度大于等于4,则取决于去掉左右边界字符后的子串是否为回文串。if (dp[i][j] && j - i + 1 > maxLen) { ... }
:如果s[i..j]
是回文串且长度大于当前记录的最长回文子串长度,则更新最长回文子串的长度和起始位置。返回结果:
return s.substr(begin, maxLen);
:根据记录的最长回文子串的起始位置和长度,返回最长回文子串。