问题描述
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
解决思路
1. 动态规划:时间空间复杂度均为O(n^2);
2. 中心扩展法:注意考虑奇数长度和偶数长度的情况,时间复杂度为O(n^2);
3. Manacher算法:
(1) 用#夹杂在字符串中,进行填充,首字符为$;
(2) 动态规划求解,记录最长回文子串的长度和中心位置;
(3) 去除多余的字符;
时间空间复杂度均为O(n).
程序
// dp
public class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int n = s.length();
int begin = 0, maxLen = 1;
boolean[][] isPalindrome = new boolean[n][n];
// 初始化
// 单个字符为回文串
for (int i = 0; i < n; i++) {
isPalindrome[i][i] = true;
}
// 连续两个相同的字符也是回文串
for (int i = 0; i < n - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {
isPalindrome[i][i + 1] = true;
begin = i;
maxLen = 2;
}
}
for (int i = n -3; i >= 0; i--) {
for (int j = i + 2; j < n; j++) {
if (s.charAt(i) == s.charAt(j)
&& isPalindrome[i + 1][j - 1]) {
isPalindrome[i][j] = true;
if (j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
}
return s.substring(begin, begin + maxLen);
}
}
public class LongestPalindromicSubstring {
// 中心匹配法, O(n^2), O(1)
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int len = s.length();
String res = "";
for (int i = 0; i < len; i++) {
String s1 = longestPString(s, i, i);
String s2 = longestPString(s, i, i + 1);
String longer = s1.length() > s2.length() ? s1 : s2;
if (longer.length() > res.length()) {
res = longer;
}
}
return res;
}
private String longestPString(String s, int i, int j) {
int low = 0, high = s.length() - 1;
while (i >= low && j <= high) {
if (s.charAt(i) != s.charAt(j)) {
break;
}
--i;
++j;
}
return s.substring(i + 1, j);
}
// Manacher算法
public String longestPalindrome2(String s) {
if (s == null || s.length() == 0) {
return "";
}
// fill $ and #
String filled = filledString(s);
int len = filled.length();
int[] r = new int[len];
r[0] = 1;
int center = 0, maxR = 0;
for (int i = 1; i < len; i++) {
int maxLeft = center + maxR;
if (i < maxLeft) {
r[i] = Math.min(r[2 * center - i], maxLeft - i);
} else {
r[i] = 1;
}
// max expand
while (i - r[i] >= 0 && i + r[i] < len
&& filled.charAt(i - r[i]) == filled.charAt(i + r[i])) {
++r[i];
}
if (r[i] > maxR) {
maxR = r[i];
center = i;
}
}
return removeSign(filled.substring(center - maxR + 1, center + maxR));
}
private String removeSign(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '#') {
continue;
}
sb.append(c);
}
return sb.toString();
}
private String filledString(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
return "$" + sb.toString();
}
}
Manacher算法图解