5. Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad"
Output: "bab"
Note: “aba” is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"
方法1: expand around center
思路:
这种方法是遍历一遍枚举中心轴,在每一个可能的中心轴向两端展开。在任意时刻,如果出现两端不等的情况,可以立刻记录一下最大值并推出。注意因为回文有可能是奇数或者偶数长度,我们需要列举所有a|b|c一共五种中心点的可能性,但是可以通过同一个函数来统一查找。这个函数会自动update 两个数值:start, maxlen,在全部查找结束后返回s.substr(start, maxlen)即所求。
Complexity
Time complexity: O(n^2), 遍历中心轴O(n), 对每一个中心轴可能需要expandO(n)次。
Space complexity: O(1)
易错点:
- right - left - 1:字符串的长度一般都是r - l + 1这里为什么减1呢?因为循环停下来的时候左右指针都指向了第一次左右不相等的情况,长度是中间串的长度。
- 如果完全没有回文串,也要保证最小的返回值是1.这里因为奇数长度的检查以i,i为左右起始,保证了至少会更新maxlen到1。
class Solution {
public:
string longestPalindrome(string s) {
if (s.size() <= 1) return s;
int start = 0, maxlen = 0;
for (int i = 0; i < s.size() - 1; i++){
searchPalindrome(s, i, i, start, maxlen);
searchPalindrome(s, i, i + 1, start, maxlen);
}
return s.substr(start, maxlen);
}
void searchPalindrome(string& s, int left, int right, int & start, int & maxlen){
while (left >= 0 && right < s.size() && s[left] == s[right]){
left --;
right ++;
}
if (right - left - 1 > maxlen){
start = left + 1;
maxlen = right - left - 1;
}
return;
}
};
方法2: dynamic programming
geeksforgeeks: https://www.youtube.com/watch?v=HBtiDHIOK9A
思路:
dp: vector<bool>dp[i][j]来记录s[i,…j] 是否是回文串。
initialization: 按照对角线来填入,也就是k = 1, 2,…,n。首先初始化所有k = 1到true,然后手动检查k = 2的情况,并更新maxlen。
transfer: 从k= 3开始,每次检查以i点开始,长度为k的字符串是否回文只需要调取dp[i + 1][j - 1], 这里j = i + k - 1。如果为true并且当前s[i] == s[j]储存为true,并且更新maxlen。
return: 记录一个全球最长字串发生的start 和maxlen,最后截取返回。
Complexity
Time complexity: O(n^2), 填入dp的大小为n ^ 2
Space complexity: O(n^2)
易错点
- j = i + k - 1:举个例子,以0 为起点,长度为3,终点是j = 3 - 0 - 1 = 2。
- 要保证maxlen在每一种长度的情况下都有更新。
class Solution {
public:
string longestPalindrome(string s) {
if (s.size() <= 1) return s;
int n = s.size();
vector<vector<bool>> dp(n, vector<bool>(n, false));
int start = 0, maxlen = 1;
// length = 1
for(int i = 0; i < n; i++){
dp[i][i] = true;
}
// length = 2
for (int i = 0; i < n - 1; i++){
if (s[i] == s[i + 1]){
dp[i][i + 1] = true;
start = i;
maxlen = 2;
}
}
// length > 2
for (int k = 3; k <= n; k ++){
// 起点
for (int i = 0; i <= n - k; i++){
// 终点
int j = i + k - 1;
// 查询dp中间段
if (dp[i + 1][j - 1] && s[i] == s[j]){
dp[i][j] = true;
if (k > maxlen) {
start = i;
maxlen = k;
}
}
//else {
// dp[i][j] = false;
//}
}
}
return s.substr(start, maxlen);
}
};