Given a string S, find the longest palindromic substring in S. You may assume that the maximum length ofS is 1000, and there exists one unique longest palindromic substring.
题解:
首先学习了一下LeetCode讨论区里的DP解法,空间复杂度O(n^2),Memory Limit Exceeded无法通过:
class Solution { public: string longestPalindrome(string s) { if(!s.length()) return NULL; int** score = new int*[s.length()]; for(int i = 0; i < s.length(); i++) score[i] = new int[s.length()]; int max = 1, start = 0, end = 0; for(int row = 0; row < s.length(); row++) for(int col = 0; col < s.length(); col++) { if(row == col) score[row][col] = 1; else if(row == col - 1 && s[row] == s[col]) { score[row][col] = 2; max = 2; start = row; end = col; } else score[row][col] = 0; } for(int outer = s.length() - 2; outer > 0; outer--) for(int inner = 0; inner < outer; inner++) { int endIndex = inner+s.length()-outer; if(s[inner] == s[endIndex] && score[inner+1][endIndex-1] > 0) { score[inner][endIndex] = score[inner+1][endIndex-1] + 1; if(score[inner][endIndex] > max) { max = score[inner][endIndex]; start = inner; end = endIndex; } } } return s.substr(start, end - start + 1); } };
A simpler approach, O(N2) time and O(1) space:
In fact, we could solve it in O(N2) time without any extra space.
We observe that a palindrome mirrors around its center. Therefore, a palindrome can be expanded from its center, and there are only 2N-1 such centers.
2N-1个中心是怎么得来的?N个字符,每个可以作为一个中心进行扩展,同时,N-1个字符之间的缝隙也可以作为中心扩展(如"abba",ab和ba中的缝隙向两边扩展得到abba),所以总共有N+N-1=2N-1个中心。这种向两边expand的方法比较直观,代码也好写,于是得到此150ms解法:
class Solution { public: string longestPalindrome(string s) { if(!s.length()) return NULL; int max = 1, start = 0, end = 0; for(int i = 1; i <= s.length(); i++) { int localMax = 1, localStart = i-1, localEnd = i-1; for(int j = 0; j < min(i-1, static_cast<int>(s.length()-i)); j++) { if(s[i-j-2] == s[i+j]) { localMax += 2; localStart = i-j-2; localEnd = i + j; } else break; } if(localMax > max) { max = localMax; start = localStart; end = localEnd; } } for(int m = 0; m < s.length()-1; m++) { if(s[m] == s[m+1]) { int localMax = 2, localStart = m, localEnd = m + 1; for(int n = 0; n < min(m, static_cast<int>(s.length()-m-2)); n++) { if(s[m-n-1] == s[m+n+2]) { localMax += 2; localStart = m - n - 1; localEnd = m + n + 2; } else break; } if(localMax > max) { max = localMax; start = localStart; end = localEnd; } } } return s.substr(start, end-start+1); } };
Java版:
尝试把字符和缝隙两种情况写在一起了,逻辑上有点混乱,最后把自己绕迷糊了:
public class Solution { public String longestPalindrome(String s) { int max = 1, start = 0, end = 0; for(int i = 0; i < s.length() * 2 - 1; i++) { int localMax = 0, localStart = 0, localEnd = 0; if(i % 2 == 0) { localMax = 1; for(int j = 0; j < Math.min(i / 2, s.length() - i / 2 - 1); j++) { if(s.charAt(i / 2 - j - 1) == s.charAt(i / 2 + j + 1)) { localMax += 2; localStart = i / 2 - j - 1; localEnd = i / 2 + j + 1; } else break; } } else { for(int j = 0; j <= Math.min(i / 2, s.length() - i / 2 - 2); j++) { if(s.charAt(i / 2 - j) == s.charAt(i / 2 + j + 1)) { localMax += 2; localStart = i / 2 - j; localEnd = i / 2 + j + 1; } else break; } } if(localMax > max) { max = localMax; start = localStart; end = localEnd; } } return s.substring(start, end+1); } }
class Solution: # @return a string def longestPalindrome(self, s): longest = 1 begin = 0 end = 0 for i in range(0, len(s)): localLongest = 1 localBegin = 0 localEnd = 0 for j in range(0, min(i, len(s)-i-1)): if s[i-j-1] == s[i+j+1]: localLongest += 2 localBegin = i - j - 1 localEnd = i + j + 1 else: break if localLongest > longest: longest = localLongest begin = localBegin end = localEnd for m in range(0, len(s)-1): if s[m] == s[m+1]: localLongest = 2 localBegin = m localEnd = m + 1 for n in range(0, min(m, len(s)-m-2)): if s[m-n-1] == s[m+n+2]: localLongest += 2 localBegin = m - n - 1 localEnd = m + n + 2 else: break if localLongest > longest: longest = localLongest begin = localBegin end = localEnd return s[begin:end+1]