Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"
思路一:求每一个子串,但是要知道一个技巧就是如何截取从最大串到最小串的判断。时间复杂度是O(N^3)
class Solution {
public String longestPalindrome(String s) {
//O(N^3)的时间复杂度
if(s.length() <= 1)
return s;
for(int i = s.length(); i >= 0; i--)
{
for(int j = 0; j <= s.length() - i; j++)
{
//关键在于这个截取的子串,由长到短,这个是最关键的
String subStr = s.substring(j, i+j);//从外向内收缩的子串,截取的子串越来越短
int count = 0;
for(int k = 0; k < subStr.length()/2; k++)
{
if(subStr.charAt(k) == subStr.charAt(subStr.length() - k -1))//判断是不是回文
count++;
}
if(count == subStr.length() / 2)//第一次出现的回文就是最长的
return subStr;
}
}
return "";
}
}
思路二:马拉车算法,时间复杂度为O(N),具体算法过程看这里:Manacher’s Algorithm 马拉车算法
马拉车的算法核心就是以当前节点为中心点,求当前这个点的最大回文串。而关键的步骤就是如何加快这个扩散。
马拉车算法分为两大部分:
1、当前节点i在右边界mx外,直接暴力扩散
2、当前节点i在右边界内:
(1)i的对称点i在最大左右边界L内,则i的回文串长度为i的回文串长度
(2)i的对称点i在最大左右边界L外,则i的回文串长度为到R的距离。
(3)i的对称点i在最大左右边界L上,则i的回文串要计算R之后的那部分是否是回文串
class Solution {
public String longestPalindrome(String s) {
//马拉车算法O(N)的时间复杂度
if(s.length()==0)
return "";
StringBuilder t = new StringBuilder("$#");
for(int i = 0; i < s.length(); i++)
{
t.append(s.charAt(i));
t.append('#');
}
t.append('@');
int[] p = new int[t.length()];
int mx = 0;
int id = 0;
int resLen = 0;
int resCenter = 0;
for(int i = 1; i < t.length()-1; ++i)
{
//关键算法步骤,mx > i表示当前点在右边界内还是外?如果是外,则重新开始扩散也就是等于1,
//当在右边界里面的时候,则判断对称点i*半径有没有超过左边界,判断两者拿个比较短,就是哪个。
//p[2 * id - i]表示没有超过的长度,mx-i表示超出的时候的长度
p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1;
//如果对称点的长度比当前的还长,后面的是否匹配要自己去算
while (((i - p[i])>=0) && ((i + p[i])<t.length()-1)
&& (t.charAt(i + p[i]) == t.charAt(i - p[i])))
++p[i];
if (mx - i < p[i]) {
mx = i + p[i];
id = i;
}
if (resLen < p[i]) {
resLen = p[i];
resCenter = i;
}
}
return s.substring((resCenter - resLen) / 2,(resCenter - resLen) / 2 + resLen - 1);
}
}