此题我曾经做过类似的(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