题目
1. 中心扩展法
观察回文串可以发现它们都是轴对称图形,对称轴可能在单个字符上,也可能在两字符之间。因此遍历一次字符串,对每个可能存在的对称轴进行判断即可。
class Solution {
public:
pair<int, int> Fun(string s, int left, int right) { // 中心扩展法搜索回文串
while(left >= 0 && right < s.size() && s[left] == s[right]) {
left--;
right++;
}
return {left + 1, right - 1};
}
string longestPalindrome(string s) {
int start = 0, end = 0;
for(int i = 0; i < s.size(); i++) {
auto [left1, right1] = Fun(s, i, i); // 回文串串为奇数
auto [left2, right2] = Fun(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); // 切割字符串
}
};
2. 动态规划法
对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。根据这样的思路,可以得到状态转移方程:
P
(
i
,
j
)
=
P
(
i
+
1
,
j
−
1
)
&
&
(
S
i
=
=
S
j
)
P(i, j) = P(i + 1, j - 1) \&\& (S_i == S_j)
P(i,j)=P(i+1,j−1)&&(Si==Sj)
现在考虑边界情况,可以发现单个字符一定时回文串,因此所有状态中均满足前一个状态的串长必定大于1,即得到j - i < 3
时所有状态均为true
。因此可以在最初时将回文串默认为首字符,此时不管何种情况,最后的所得串一定满足条件。
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
int start = 0, len = 1; // 串的默认值
bool dp[n][n];
for(int j = 1; j < n; ++j) { // 按列遍历
for(int i = 0; i < j; ++i) { // 只需遍历上三角
if(s[i] != s[j])
dp[i][j] = false;
else if(j - i < 3) // 因为提前考虑了边界,因此不需要将对角元素初始化为true
dp[i][j] = true;
else dp[i][j] = dp[i+1][j-1]; // 状态转移
if(dp[i][j] && j - i + 1 > len) { // 更新最优解
start = i;
len = j - i + 1;
}
}
}
return s.substr(start, len); // 切割字符串
}
};