思路:
方法一:暴力,时间复杂度O(n^3),空间复杂度O(1)
不断判断子串是否回文。
//Longest Palindromic Substring
string longestPalindrome(string s) {
int length=s.size();
int maxLength=1;
int start=0;
for(int i=0;i<length;i++) {
for(int j=i+1;j<length;j++) {
int tmp1,tmp2;
for(tmp1=i,tmp2=j;tmp1<tmp2;tmp1++,tmp2--) {
if(s.at(tmp1)!=s.at(tmp2)) break;
}
if(tmp1>=tmp2 && j-i+1 >maxLength) {
maxLength = j-i+1;
start=i;
}
}
}
if(maxLength>0) {
return s.substr(start,maxLength);
}
return NULL;
}
方法二:DP,时间复杂度O(n^2),空间复杂度,O(n^2)
p[i][j]表示以i开始j结束的子串是否满足回文:
p[i][j]==1 是回文子串;
p[i][j]!=1 不是回文子串;
状态转移方程:
p[i][i]=1;
p[i][i+1]=1 : if s[i]==s[i+1]
p[i][j]=1 : if s[i]==s[j] && p[i+1][j-1]=1
class Solution {
public:
string longestPalindrome(string s) {
int n = s.length();
int longestBegin = 0;
int maxLen = 1;
bool table[1000][1000] = {false};
for(int i=0;i<n;i++) {
table[i][i] = 1;
}
for(int i=0;i<n-1;i++) {
if(s[i] == s[i+1]) {
table[i][i+1]=1;
maxLen=2;
longestBegin=i;
}
}
for(int len=3;len<=n;len++) {
for(int i=0;i<n-len+1;i++) {
int j=i+len-1;
if(s[i]==s[j] && table[i+1][j-1]==1) {
table[i][j]=1;
maxLen=len;
longestBegin=i;
}
}
}
return s.substr(longestBegin,maxLen);
}
};
方法三:中心扩展法
设字符串s长度为n
对于长度为奇数的回文子串,沿着中心字符轴对称,可能的中心点共有n个;
对于长度为偶数的回文子串,沿着中心空字符轴对称,可能的中心点共有n-1个;
所以我们可以一个一个中心点的去试探,判断以此为中心的子串是否是回文子串。
class Solution {
public:
string longestPalindrome(string s) {
const int length=s.size();
if(length == 0) return "";
int maxLength=1;
int start=0;
for(int i=0;i<length;i++) {
int j=i-1,k=i+1;
while(j>=0 && k<length && s[j]==s[k]) {
if(k-j+1 > maxLength) {
maxLength=k-j+1;
start=j;
}
j--;
k++;
}
}
for(int i=0;i<length;i++) {
int j=i,k=i+1;
while(j>=0 && k<length && s[j]==s[k]) {
if(k-j+1 > maxLength) {
maxLength=k-j+1;
start=j;
}
j--;
k++;
}
}
return s.substr(start,maxLength);
}
};
方法四:Manacher‘s Algorithm
这个算法的时间复杂度在O(n),空间复杂度也为O(n),学习完这个算法觉得设计的太巧妙了!充分利用了回文串的对称性。
看了好几篇介绍的博文,这篇写的最易理解:《Manacher's algorithm:优雅的求最长回文子串》
class Solution {
public:
string preProcess(string s) {
int n=s.length();
if(n==0) return "^$";
string ret="^";
for(int i=0;i<n;i++) {
ret += "#"+s.substr(i,1);
}
ret += "#$";
return ret;
}
string longestPalindrome(string s) {
string T = preProcess(s);
const int n = T.length();
int P[n];
int center = 0, mx = 0;
for(int i=1;i<n-1;i++) { //i从第一个“#”循环到到最后一个“#”
int i_mirror = 2*centor-i;
//P[i] = (mx > i) ? min(P[i_mirror], mx - i) : 0;
if(mx > i) {
if(i+P[i_mirror] < mx) {
P[i] = P[i_mirror];
}else {
P[i] = mx - i;
}
}else {
P[i] = 0;
}
//calculate P[i] at i
while(T[i + 1 + P[i]] == T[i - 1 - P[i]]) {
P[i]++;
}
//update center and mx
if(i + P[i] > mx) {
center = i;
mx = i + P[i];
}
}
//find the maximum element in P
int max_len = 0;
int centor_index = 0;
for(int i=1; i<n-1; i++) {
if(P[i]>max_len) {
max_len = P[i];
centor_index = i;
}
}
return s.substr((centor_index - 1 - max_len)/2, max_len);
}
};