一. 题干
给定一个字符串s,找到s中最长的回文子字符串。 您可以假设s的最大长度为1000。
例1:
输入:“babad”
输出:“bab”
注意:“aba”也是一个有效的答案。
例2:
输入:“cbbd”
输出:“bb”
二. 思路
第一眼看到这个题目,想到的是反转字符串找相同的序列即可,然后发现具体实施更麻烦了。
让我们思考回文序列的规律:
- aa
- aba
- abba
无非是上面的三种形式。
假设我们的字符串是’aba’ 这种形式:
a b a
我们讲从第某个字符’b’(下角标为index)开始遍历, 比较他的左右两个字符(即 before=index-1 和 after=index+1)是否相等, 这样就很容易找出最长的回文子序列了。
值得注意的是,当我们的回文形式是’abba’时,注意该回文序列是双轴形式,那就需要调整相应的before和after的位置。
算法如下:
public String longestPalindrome(String s) {
if (s == null || s.isEmpty()) return "";
String longest = s.substring(0, 1);
for(int i =1; i < s.length(); i++) {
int before = i-1, after = i+1;
while(true) {
if (before>=0 && s.charAt(before) == s.charAt(i)) {
before--;
} else {
break;
}
}
while(true) {
if (after <= s.length()-1 && s.charAt(after) == s.charAt(i)) {
after++;
} else {
break;
}
}
while(true) {
if (before<0 || after > s.length()-1) break;
if (s.charAt(before) != s.charAt(after)) break;
before--;
after++;
}
if (before != i-1) {
// found a palindrome
String sub = s.substring(before+1, after);
if (sub!=null && sub.length()>longest.length()) {
longest = sub;
}
}
}
return longest;
}
当然这个算法很不优雅。有没有一种更简单,快捷的方式呢,有的,还是O(n)
三. 进阶
在采用上面的算法时,曾想过能否直接算出某个字符左右回文值。比如 abcwcba :
a b c w c b a
0 1 2 3 2 1 0
按照这个思路也是可以实现的。但是实现起来格外麻烦,需要很多额外空间存储标记数,所以放弃了。
但是在网上查了后,发现这个思路是没有问题,只是需要更改下方式:
如上图,这就是 manacher’s algorithm . 有兴趣的童鞋可以百度下,这里就不贴代码了。