此题我曾经做过类似的(http://hi.baidu.com/lautsie/item/459a182eeddc568e6f2cc34a)但还是忘了,可见这个算法还是很tricky的。其实O(n^2)的算法还是能想到的,就是遍历每个字符,然后从该字符向两旁扩,寻找最长子串。但居然有O(n)的方法,见下面链接。
http://www.felix021.com/blog/read.php?2040
最后的代码其实可以做优化,比如最后不需要再遍历一边p[],但复杂度不变,又不是关键,就这样吧~
public class Solution { public String longestPalindrome(String s) { // Start typing your Java solution below // DO NOT write main() function StringBuilder sb = new StringBuilder(); sb.append('#'); for (int i = 0; i < s.length(); i++) { sb.append(s.charAt(i)); sb.append('#'); } String ss = sb.toString(); int[] p = new int[ss.length()]; int mx = 0; int id = 0; for (int i = 0; i < ss.length(); i++) { p[i] = mx > i ? Math.min(p[id * 2 -i], mx - i) : 1; while (i+p[i] < ss.length() && i - p[i] >=0) { if (ss.charAt(i + p[i]) == ss.charAt(i-p[i])) { p[i]++; } else { break; } } if (i + p[i] > mx) { mx = i + p[i]; id = i; } } // process result int maxIndex = 0; int maxLen = 0; for (int i = 0; i < ss.length(); i++) { if( p[i] > maxLen) { maxLen = p[i]; maxIndex = i; } } StringBuilder r = new StringBuilder(); for (int i = maxIndex - p[maxIndex] + 1; i <= maxIndex + p[maxIndex] - 1; i++) { if(ss.charAt(i) != '#') { r.append(ss.charAt(i)); } } return r.toString(); } }
第二刷,不强求用Manacher方法。使用n^2的方法,要注意长度为奇数和偶数两种情况。
class Solution { public: string longestPalindrome(string s) { int maxLen = 0; int idx = 0; for (int i = 0; i < s.length(); i++) { for (int len = 0; i - len >= 0 && i+len < s.length(); len++) { if (s[i-len] != s[i+len]) break; if (maxLen < len * 2 + 1) { maxLen = len * 2 + 1; idx = i - len; } } for (int len = 0; i - len >= 0 && i+len+1 < s.length(); len++) { if (s[i-len] != s[i+len+1]) break; if (maxLen < (len + 1) * 2) { maxLen = (len + 1) * 2; idx = i - len; } } } return s.substr(idx, maxLen); } };
python3的dp,最后超时了。还是中心扩散法好。
class Solution: def longestPalindrome(self, s: str) -> str: palindromeDict = {} result = '' length = 1 while length <= len(s): for idx in range(len(s)): if idx + length <= len(s): if length == 1: palindromeDict[(idx, length)] = True if palindromeDict[(idx, length)] and length > len(result): result = s[idx : idx + length] elif length == 2: palindromeDict[(idx, length)] = (s[idx] == s[idx + 1]) if palindromeDict[(idx, length)] and length > len(result): result = s[idx : idx + length] else: # length > 2 palindromeDict[(idx, length)] = (s[idx] == s[idx + length - 1]) and palindromeDict[(idx + 1, length - 2)] if palindromeDict[(idx, length)] and length > len(result): result = s[idx : idx + length] length += 1 return result
Python3的中心扩散法
class Solution: def longestPalindrome(self, s: str) -> str: result = '' for i in range(len(s) * 2 - 1): center = i // 2 if i % 2 == 1: left = center right = center + 1 else: # i % 2 == 0 left = center right = center while left >= 0 and right < len(s): if s[left] == s[right]: if right - left + 1 > len(result): result = s[left : right + 1] left -= 1 right += 1 else: break return result