Description:
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"
描述:
给定字符串s,查找s的最长回文子串。
假设字符串s的最大长度为1000.
示例1:
输入: “babad” 输出: "bab" 注意:“aba”也是有效的答案
示例2:
输入:“cbbd” 输出: “bb”
方法一:暴力破解
首先,明确回文的概念。“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。
遍历字符串s的每一个子串,并判断该子字符串是否为回文。
class Solution {
public:
string longestPalindrome(string s) {
int len = s.length();
string str;
int maxLen = 0;
if(len == 0) return s;
for(int i = 0; i < len; i++) {
for(int j = i + 1; j <= len; j++) {
int len = palindromeLen(s, i, j);
if(len >= maxLen) {
maxLen = len;
str = s.substr(i, j - i);
}
}
}
return str;
}
int palindromeLen(string str, int start, int end) {
int s = start;
int e = end - 1;
while(s <= e) {
if(str[s++] != str[e--])
return 0;
}
return end - start;
}
};
该方法的时间复杂度为O(n3),空间复杂度为O(n)。运行时间为1796ms。
方法2:动态规划
首先,我们考虑如何减少重复比较的次数。以“ababa”为例,如果我们已经知道“bab”为回文,那么“ababa”也是回文,因为“bab”首端和末端的字符相等,均为字符‘a’。
显而易见地,
P(i,j) = true, 如果Si,...,Sj为回文串,反之,P(i,j) = false
因此,P(i,j) = (P(i+1, j-1) and Si == Sj)。
并且,P(i,i) = true, 当Si == Si+1时P(i, i+1) = true。
class Solution {
public:
string longestPalindrome(string s) {
int len = s.length();
if(len == 0 || len == 1)
return s;
bool p[len][len];
for(int i = 0; i < len; i++) {
for(int j = 0; j < len; j++) {
p[i][j] = false;
}
}
int maxLen = 0;
string ans;
for(int l = 0; l < len; l++) {
for(int i = 0; i < len - l; i++) {
int j = i + l;
if(s[i] == s[j] && (l < 2 || p[i+1][j-1])) {
p[i][j] = true;
if(l + 1 > maxLen) {
maxLen = l + 1;
ans = s.substr(i, l+1);
}
}
}
}
return ans;
}
};
本方法的时间复杂度为O(n2),空间复杂度为O(n),运行时间为108ms。
方法三:中心扩展法
中心扩展法的核心思想是选定一个中心,并不断向两端扩展来判断是否是回文字符串。
对于长度为n的字符串,共有2n-1个中心:首先,可以选定每个字符为中心,并不断向两端扩展,共有n中选法,此时选定的是“aba”型的回文字符串;其次,可以选定每对字符中间位置为中心,共有n-1中选法,此时选定的是“abba”型回文字符串。
class Solution {
public:
string longestPalindrome(string s) {
int len = s.length();
if(len == 0 || len == 1)
return s;
string ans;
int maxLen = 0;
for(int i = 0; i < len - 1; i++) {
int len1 = isPalindrome(s, i, i);
if(len1 > maxLen) {
maxLen = len1;
ans = s.substr(i - len1 / 2, len1);
}
int len2 = isPalindrome(s, i, i + 1);
if(len2 > maxLen) {
maxLen = len2;
ans = s.substr(i + 1- len2 / 2, len2);
}
}
return ans;
}
int isPalindrome(string s, int start, int end) {
int len = s.length();
while(start >= 0 && end < len) {
if(s[start] == s[end]) {
start--;
end++;
} else {
break;
}
}
return end - start - 1;
}
};
本方法的时间复杂度为O(n2),空间复杂度为O(n),运行时间为12ms。