这一题 是LeetCode 的第五道题,链接如下:
5. 最长回文子串
常见的解法
动态规划
定义一个二维数组 boolean[][]
,boolean[i][j]
表示的是从 i 到 j 是不是回文串,其中 i 和 j 分为 以下几种情况:
- “aaa”,“aba”:这两种都是一个回文串
- “eabce”:此时虽然最后一个和第一个是相等的,但是 i + 1 和 j - 1 却不是相等的,因此不是回文串。
思路一:
从左到右一直遍历
for(int right = 0; right < len; right++){
for(int left = 0; left < right; left++){
if(s.charAt(left) != s.charAt(right)){
continue;
}
if(left == right){
dp[left][right] = true;
} else if(right - left <= 2){
dp[left][right] = true;
} else {
dp[left][right] = dp[left + 1][right - 1];
}
if(dp[left][right] && right - left + 1 > maxLen){
start = left;
maxLen = right - left + 1;
}
}
}
此种方法,只需要定位到 start 和 maxLen,就可以得到最终的最长的回文子串
思路二
定长循环,从左边开始,依次间隔 N 个字符进行判断,因为一个字符肯定是回文,所以最短的是从 2 开始,最长是整个字符串。
for(int step = 2; step <= charArray.length; step++){
for(int left = 0; left < charArray.length; left++){
int right = left + step - 1;
if(right >= charArray.length){
break;
}
if(charArray[left] == charArray[right]){
if(right - left < 3){
dp[left][right] = true;
} else {
dp[left][right] = dp[left + 1][right - 1];
}
} else {
dp[left][right] = false;
}
if(dp[left][right] && right - left + 1 > maxLen){
start = left;
maxLen = right - left +1;
}
}
}
两种方法最后都是调用 s.substring(start,start + maxLen)
得到最长的回文。
中心扩展法
中心扩展法的思想就是遍历一遍,然后从当前下标向两边扩散,需要注意的是扩散的需要区分两种情况
a*a
这种就简单很多,left++,right–即可
baab
如果此时的下标是 1,那么left = 1,right 就需要 +1 开始遍历了
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
Manacher 算法
有点复杂。。