[LeetCode] 5. Longest Palindromic Substring 最长回文子串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd" Output: "bb"
最长回文子串Longest palindromic substring, 最长回文子串或最长对称因子问题是在一个字符串中查找一个最长连续子串,这个子串必须是回文。例如“banana”最长回文子串是“anana”。最长回文子串算法不应当与最长回文子序列算法混淆。
解法1: 枚举(enumerate): 基于中心点枚举的算法, 遍历数组,以其中的1个元素或者2个元素作为palindrome的中心,通过辅助函数,寻找能拓展得到的最长子字符串。外层循环 O(n),内层循环O(n),因此时间复杂度 Time O(n^2),因为只需要存最长palindrome子字符串本身,空间更优化:Space O(1)
解法2:动态归化(DP):
State: dp[i][j], s[i]到s[j]是否构成一个回文
Function: dp[i][j] = s[i] == s[j] &&(j - i <= 2 || dp[i + 1][j - 1])
Initialize: dp[i][j] = true when j - i <= 2
Return: longest substring: longest = s[i, j + 1]
解法3:Manacher's Algorithm,可以达到 O(n) 的线性时间复杂度。
Manacher算法可参考:
Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
Longest Palindromic Substring Part II
解法4: 以任意一个字符i为中心点,向两边扩展,直到不是回文为止,计算长度,保留最大长度的字符串。扩展的时候分为奇数和偶数两种情况。
Java:
public class Solution { private int lo, maxLen; public String longestPalindrome(String s) { int len = s.length(); if (len < 2) return s; for (int i = 0; i < len-1; i++) { extendPalindrome(s, i, i); //assume odd length, try to extend Palindrome as possible extendPalindrome(s, i, i+1); //assume even length. } return s.substring(lo, lo + maxLen); } private void extendPalindrome(String s, int j, int k) { while (j >= 0 && k < s.length() && s.charAt(j) == s.charAt(k)) { j--; k++; } if (maxLen < k - j - 1) { lo = j + 1; maxLen = k - j - 1; } } }
Java: 枚举(enumerate), Time: O(n^2), Space: O(1)
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; } }
Java: DP, Time: O(n^2), Space: O(n^2)
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); } }
Java: Manacher's Algorithm, Time: O(n), Space: O(n)
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(); } }
Python:
class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ res = "" for i in xrange(len(s)): # odd case, like "aba" tmp = self.helper(s, i, i) if len(tmp) > len(res): res = tmp # even case, like "abba" tmp = self.helper(s, i, i+1) if len(tmp) > len(res): res = tmp return res # get the longest palindrome, l, r are the middle indexes # from inner to outer def helper(self, s, l, r): while l >= 0 and r < len(s) and s[l] == s[r]: l -= 1; r += 1 return s[l+1:r]
Python:
# Manacher's Algorithm class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ def preProcess(s): if not s: return ['^', '$'] T = ['^'] for c in s: T += ['#', c] T += ['#', '$'] return T T = preProcess(s) P = [0] * len(T) center, right = 0, 0 for i in xrange(1, len(T) - 1): i_mirror = 2 * center - i if right > i: P[i] = min(right - i, P[i_mirror]) else: P[i] = 0 while T[i + 1 + P[i]] == T[i - 1 - P[i]]: P[i] += 1 if i + P[i] > right: center, right = i, i + P[i] max_i = 0 for i in xrange(1, len(T) - 1): if P[i] > P[max_i]: max_i = i start = (max_i - 1 - P[max_i]) / 2 return s[start : start + P[max_i]]
C++:
class Solution { public: string longestPalindrome(string s) { if (s.empty()) return ""; if (s.size() == 1) return s; int min_start = 0, max_len = 1; for (int i = 0; i < s.size();) { if (s.size() - i <= max_len / 2) break; int j = i, k = i; while (k < s.size()-1 && s[k+1] == s[k]) ++k; // Skip duplicate characters. i = k+1; while (k < s.size()-1 && j > 0 && s[k + 1] == s[j - 1]) { ++k; --j; } // Expand. int new_len = k - j + 1; if (new_len > max_len) { min_start = j; max_len = new_len; } } return s.substr(min_start, max_len); } };
类似题目:
[LeetCode] 125. Valid Palindrome 有效回文
[LeetCode] 9. Palindrome Number 验证回文数字
[LeetCode] 516. Longest Palindromic Subsequence 最长回文子序列
[LeetCode] 647. Palindromic Substrings 回文子字符串
All LeetCode Questions List 题目汇总