题目:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
思路1:
动态规划,对长度从1到len的字符串判断是否为回文,时间复杂度O(n*n),空间复杂度O(n*n)。
Java代码:
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
int[][] dp = new int[1010][1010];
for(int i = 0; i < len; ++i) {
dp[i][i] = 1;
}
int pos1=0,pos2=0,ans=1;
for(int l = 2; l <= len; ++l) {
for(int i = 0; i <= len - l; ++i) {
int j = i + l - 1;
if(s.charAt(i) == s.charAt(j)) {
if(l == 2) {
dp[i][j] = 2;
} else {
if(dp[i+1][j-1] == j - i - 1)
dp[i][j] = dp[i+1][j-1] + 2;
}
}
if(dp[i][j] > ans) {
ans = dp[i][j];
pos1 = i;
pos2 = j;
}
}
}
String res = s.substring(pos1,pos2+1);
return res;
}
}
思路2:
Manacher(马拉车)算法。它每个回文串都是对称的特点,在两个字符串之间插入某一个字符串比如“#”,用一个数组记录每个位置所能达到的最大的回文串长度。时间复杂度O(n),空间复杂度O(n)。
如:
abcdcba :
#a#b#c#d#c#b#a#
121212181212121
最大回文串的长度为8-1=7
Java代码:
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
int[] p = new int[2048];
char[] x = new char[2048];
x[0] = '$';
x[1] = '#';
int cnt = 1;
for(int i = 0; i < len; ++i) {
x[++cnt] = s.charAt(i);
x[++cnt] = '#';
}
int ma = 0, pos = 0, ans = 0, anspos = 0;
for(int i = 1; i <= cnt; ++i) {
if(i < ma) p[i] = Math.min(p[pos * 2 - i], ma - i);
else p[i] = 1;
while(x[i+p[i]] == x[i-p[i]]){
p[i]++;
}
if(ma < i + p[i]) {
ma = i + p[i];
pos = i;
}
if(ans < p[i]) {
ans = p[i] - 1;
anspos = i;
}
}
String res = "";
if (x[anspos] == '#') {
int zz = ans / 2;
for(int i = anspos - zz*2+1; i <= anspos + zz*2-1; ++i) {
if(x[i]=='#')continue;
res += x[i];
}
} else {
int zz = (ans - 1) / 2;
int pos1 = anspos/2 - 1 - zz, pos2 = anspos/2 - 1 + zz;
for(int i = pos1; i <= pos2; ++i) {
if(s.charAt(i) == '#')continue;
res += s.charAt(i);
}
}
return res;
}
}