![bf91a895a16e6dad55a5cbe6d065c0da.png](https://i-blog.csdnimg.cn/blog_migrate/816ce9ef7d5d85cf2d81cddda7654891.jpeg)
LintCode 200. 微软高频面试题:最长回文子串
LintCode 领扣www.lintcode.com题目描述
给出一个字符串(假设长度最长为1000),求出它的最长回文子串,你可以假定只有一个满足条件的最长回文串。
样例1:
输入:"abcdzdcab"
输出:"cdzdc"
样例2:
输入:"aba"
输出:"aba"
挑战
O(n2) 时间复杂度的算法是可以接受的,如果你能用 O(n) 的算法那自然更好。
题解
Java:
基于中心点枚举的算法,时间复杂度 O(n^2)
/**
* This reference program is provided by @jiuzhang.com
* Copyright is reserved. Please indicate the source for forwarding
*/
public class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int start = 0, len = 0, longest = 0;
for (int i = 0; i < s.length(); i++) {
len = findLongestPalindromeFrom(s, i, i);
if (len > longest) {
longest = len;
start = i - len / 2;
}
len = findLongestPalindromeFrom(s, i, i + 1);
if (len > longest) {
longest = len;
start = i - len / 2 + 1;
}
}
return s.substring(start, start + longest);
}
private int findLongestPalindromeFrom(String s, int left, int right) {
int len = 0;
while (left >= 0 && right < s.length()) {
if (s.charAt(left) != s.charAt(right)) {
break;
}
len += left == right ? 1 : 2;
left--;
right++;
}
return len;
}
}
使用 Manancher's Algorithm,可以在 O(n) 的时间内解决问题
/**
* This reference program is provided by @jiuzhang.com
* Copyright is reserved. Please indicate the source for forwarding
*/
public class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
// abc => #a#b#c#
String str = generateString(s);
int[] palindrome = new int[str.length()];
int mid = 0, longest = 1;
palindrome[0] = 1;
for (int i = 1; i < str.length(); i++) {
int len = 1;
if (mid + longest > i) {
int mirrorOfI = mid - (i - mid);
len = Math.min(palindrome[mirrorOfI], mid + longest - i);
}
while (i + len < str.length() && i - len >= 0) {
if (str.charAt(i - len) != str.charAt(i + len)) {
break;
}
len++;
}
if (len > longest) {
longest = len;
mid = i;
}
palindrome[i] = len;
}
longest = longest - 1; // remove the extra #
int start = (mid - 1) / 2 - (longest - 1) / 2;
return s.substring(start, start + longest);
}
private String generateString(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();
}
}
基于动态规划的算法,时间复杂度 O(n^2),但是会耗费额外的 O(n^2) 的空间复杂度
/**
* This reference program is provided by @jiuzhang.com
* Copyright is reserved. Please indicate the source for forwarding
*/
public class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int n = s.length();
boolean[][] isPalindrome = new boolean[n][n];
int longest = 1, start = 0;
for (int i = 0; i < n; i++) {
isPalindrome[i][i] = true;
}
for (int i = 0; i < n - 1; i++) {
isPalindrome[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
if (isPalindrome[i][i + 1]) {
start = i;
longest = 2;
}
}
for (int i = n - 1; i >= 0; i--) {
for (int j = i + 2; j < n; j++) {
isPalindrome[i][j] = isPalindrome[i + 1][j - 1] &&
s.charAt(i) == s.charAt(j);
if (isPalindrome[i][j] && j - i + 1 > longest) {
start = i;
longest = j - i + 1;
}
}
}
return s.substring(start, start + longest);
}
}
Python:
基于区间型动态规划的解法
# This reference program is provided by @jiuzhang.com
# Copyright is reserved. Please indicate the source for forwarding
class Solution:
"""
@param s: input string
@return: the longest palindromic substring
"""
def longestPalindrome(self, s):
if not s:
return ""
n = len(s)
is_palindrome = [[False] * n for _ in range(n)]
for i in range(n):
is_palindrome[i][i] = True
for i in range(1, n):
is_palindrome[i][i - 1] = True
longest, start, end = 1, 0, 0
for length in range(1, n):
for i in range(n - length):
j = i + length
is_palindrome[i][j] = s[i] == s[j] and is_palindrome[i + 1][j - 1]
if is_palindrome[i][j] and length + 1 > longest:
longest = length + 1
start, end = i, j
基于中心线枚举的方法
# This reference program is provided by @jiuzhang.com
# Copyright is reserved. Please indicate the source for forwarding
class Solution:
"""
@param s: input string
@return: the longest palindromic substring
"""
def longestPalindrome(self, s):
if not s:
return ""
longest = ""
for middle in range(len(s)):
sub = self.find_palindrome_from(s, middle, middle)
if len(sub) > len(longest):
longest = sub
sub = self.find_palindrome_from(s, middle, middle + 1)
if len(sub) > len(longest):
longest = sub
return longest
def find_palindrome_from(self, string, left, right):
while left >= 0 and right < len(string) and string[left] == string[right]:
left -= 1
right += 1
return string[left + 1:right]
C++:
/**
* This reference program is provided by @jiuzhang.com
* Copyright is reserved. Please indicate the source for forwarding
*/
class Solution {
public:
/*
题意为求最长回文子串, 直接枚举子串首尾位置再判断是否会问,时间复杂度为O(N^3),
换个思路,枚举回文串的对称中心位置,向两侧扫描检测最长回文长度时间复杂度为O(N^2)
对于最长回文子串问题有对应O(N)算法--Manacher算法
笔者觉得面试中应当不会有这么高的要求,有兴趣可以自行了解该算法
*/
string longestPalindrome(string s) {
string str = "", ans = "";
int len = s.length();
int maxl = -1, cnt;
for (int i = 0; i < len; i++) {
str += '#';
str += s[i];
}
str += '#';
// 将原字符串扩展成#a#b#的形式可以直接枚举长度,不用考虑回文串长度的奇偶性
for (int i = 1; i < 2 * len; i++) {
cnt = 0;
while ((i - cnt >= 0) && (i + cnt <= 2 * len) && (str[i - cnt] == str[i + cnt]))
cnt++;
cnt--;
if (cnt > maxl) {
maxl = cnt;
ans = s.substr((i - cnt) / 2, (i + cnt) / 2 - (i - cnt) / 2);
}
}
return ans;
}
};
更多大厂高频考题,请点击LintCode进行在线评测