概述
找一个序列的最长回文串方法有很多,暴力求解,dp,中心扩散,还有Manacher(马拉车)等,中心扩散的时间复杂度O(n^2),而且相比于dp,不需要开辟额外的空间,实际操作上比dp稍微高效一点。又比较容易理解。
一般的方法
如果是判断是否为回文串,我们一般这样做
public boolean valid(char[] str, int l, int r){
while (l < r){
if (str[l++] != str[r--]){
return false;
}
}
return true;
}
中心扩散
中心扩散则是选取中点,向两边扩散,以确定回文串最大长度的方法。要注意中心是一个还是两个的情况,即对字符串长度奇偶性的讨论。
leetcode5
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
用中心扩散法,返回最大长度,我们可以通过选取的中点倒推出字符串的起点。
public class Solution {
public String longestPalindrome(String s){
int len = s.length();
char[] str = s.toCharArray();
int begin = 0, end = 0;
for (int i = 0; i < len; i++) {
int len1 = expand(str, i, i);
int len2 = expand(str, i, i + 1);
int max_len = Math.max(len1, len2);
if (max_len > end - begin){
begin = i - (max_len - 1) / 2;
end = i + max_len / 2;
}
}
return s.substring(begin, end + 1);
}
public int expand(char[] s, int l, int r){
while (l >= 0 && r < s.length && s[l] == s[r]){
l--;
r++;
}
//注意这里s[l] != s[r],返回的长度应当注意
return r - l - 1;
}
}
leetcode647
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
稍作改动,我们遍可以解决这个问题了,因为中心扩散法实际上相当于遍历了所有的回文串,我们只需要多引入一个计数器即可
class Solution {
int res = 0;
public int countSubstrings(String s) {
char[] chars = s.toCharArray();
for(int i = 0; i < chars.length; ++i){
expand(chars, i, i);
expand(chars, i, i + 1);
}
return res;
}
public void expand(char[] s, int l, int r){
while(l >= 0 && r < s.length){
if(s[l--] != s[r++]){
break;
}
res++;
}
}
}