题目描述:
给出一个字符串(假设长度最长为1000),求出它的最长回文子串,你可以假定只有一个满足条件的最长回文串。
样例
给出字符串 "abcdzdcab"
,它的最长回文子串为 "cdzdc"
。
O(n2) 时间复杂度的算法是可以接受的,如果你能用 O(n) 的算法那自然更好。
原题链接
LeetCode: https://leetcode.com/problems/longest-palindromic-substring/description/
LintCode: http://www.lintcode.com/zh-cn/problem/longest-palindromic-substring/#
解法一:
这种作法可用通过Lintcode的测试,但是无法通过LeetCode
public class Solution {
/*
* @param s: input string
*
* @return: the longest palindromic substring
*/
public String longestPalindrome(String s) {
// write your code here
String res = "";
if (s == null || s.length() == 0) {
return "";
}
for (int i = s.length() - 1; i >= 0; i--) { // i是子字符串的长度
int j = 0;
while (j + i < s.length()) {
if (s.charAt(j) == s.charAt(j + i)) { // 判断子字符串首尾是否相同(第一次筛选)
String s2 = s.substring(j, j + i + 1);
if (s2.length() > res.length()) { // 判断子字符串长度是否比上一个回文子串长(第二次筛选)
if (isPalindrome(s2)) { // 判断是否是回文字符串
res = s2;
}
}
}
j++;
}
}
return res;
}
public boolean isPalindrome(String s) {
boolean b = true;
for (int i = 0; i < s.length() / 2; i++) {
if (s.charAt(i) != s.charAt(s.length() - 1 - i)) {
b = false;
}
}
return b;
}
};
解法二:
这种解法同样可以通过Lintcode的测试,但无法通过LeetCode……
/**
*
* 对于每个子串的中心(可以是一个字符,或者是两个字符的间隙,比如串abc,中心可以是a,b,c,或者是ab的间隙,bc的间隙)往两边同时进行扫描,
* 直到不是回文串为止。假设字符串的长度为n,那么中心的个数为2*n-1(字符作为中心有n个,间隙有n-1个)。
* 对于每个中心往两边扫描的复杂度为O(n),所以时间复杂度为O((2*n-1)*n)=O(n^2),空间复杂度为O(1),代码如下:
*/
public class Solution {
public String longestPalindrome(String s) {
// write your code here
String res = "";
if (s == null || s.length() == 0) {
return "";
}
int maxLen = 0;
for (int i = 0; i < 2 * s.length() - 1; i++) {
int left = i / 2;
int right = i / 2;
if (i % 2 == 1) {
right++;
}
String str = lengthOfPalindrome(s, left, right);
if (maxLen < str.length()) {
maxLen = str.length();
res = str;
}
}
return res;
}
public String lengthOfPalindrome(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return s.substring(left + 1, right);
}
}
解法三:
此解法来自九章算法,可以通过Lintcode和LeetCode的测试。
public class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int length = s.length();
int max = 0;
String result = "";
for (int i = 1; i <= 2 * length - 1; i++) { // 2*length-1个中心
int count = 1;
while (i - count >= 0 && i + count <= 2 * length && get(s, i - count) == get(s, i + count)) {
// i-count:左边界。 i+count:右边界
count++;
}
count--; // there will be one extra count for the outbound #
if (count > max) {
result = s.substring((i - count) / 2, (i + count) / 2); // 回文子串
max = count;
}
}
return result;
}
private char get(String s, int i) {
if (i % 2 == 0) { // i是偶数,表示这个中心为间隙
return '#';
} else { // i是奇数,表明中心是字符
return s.charAt(i / 2);
}
}
}