1 算法描述
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
示例 3:
输入:s = "a" 输出:"a"
示例 4:
输入:s = "ac" 输出:"a"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成
2 解题思路
方案一:中心扩展法
中心扩展法的思路是一次遍历字符串中的字符,以字符作为中心点像左右两侧扩展,左右两侧元素相等继续扩展,如果不相等或者一方扩展到字符串开头或结尾的位置,结束遍历并记下回文子串的长度,和最长的回文子串长度比较,留下最长的。
中心扩展法会分两种情况,
情况一:子串长度是奇数,以中心点为中心对称,如下图所示:
情况二:子串长度是偶数,依次对称,如下图所示:
a,b,c,c,b,a是一个回文串,然而找不到对称中心,这样以一个元素为中心向两边扩展就不好用了,这里有一种比较方便的处理方式,就是对a,b,c,c,b,a进行填充,比如说用#进行填充,填充之后就又成了一个中心对称的回文串,因此对于一个串进行处理时,先进行扩充,这样可以使中心扩展时比较方便,不用对非中心对称的子串进行特殊处理。假设填充前的子串长度为 maxLen 那么扩充或的长度为:2 * maxLen+1,由这个关系也可以很方便的得到扩充前回文串的长度。
中心扩展法求最长回文子串长度的编码如下所示:
/**
* @Author boy
* @Description 中心扩展法
* @Date 2021/12/16 9:57 AM
* @Param [str]
* @return int
*/
public static int PalindRomeSubString(String str){
//字符中间插入 #
StringBuffer sb = new StringBuffer();
for (int i=0;i<str.length();i++){
sb.append("#");
sb.append(str.charAt(i));
}
sb.append("#");
//字符串转化为字符数组
char[] c = sb.toString().toCharArray();
//最长回文子串的长度
int maxLen = 0;
//遍历逐个字符,以字符作为中心点向两边扩展,找到最长回文子串
for (int i=0;i<c.length;i++){
maxLen = Math.max(subpalidromelen(c,i),maxLen);
}
return maxLen;
}
/**
* @Author boy
* @Description 中心扩展函数
* @Date 2021/12/16 10:02 AM
* @Param [chs, i],chs为字符数组,i为中心扩展的中心位置
* @return int
*/
public static int subpalidromelen(char []chs,int i){
int len = 0;//回文长度
int left = i;//左指针
int right = i;//右指针
while (left>=0 && right<chs.length && chs[left]==chs[right]){
left--;
right++;
len ++;
}
return --len;//填充之后的串,填充之前的回文子串值为len-1
}
中心扩展法的时间复杂度是O(n^2),空间复杂度是O(1)。
方案二:动态规划
解题思路:使用二维数组 f[i][j] 保存子串从i到j是否是回文子串,在求 f[i][j] 的时候如果 j-i >=2时,如果 f[i][j] 为回 文,那么 f[i+1][j-1] 也一定为回文,否则 f[i][j] 不是回文。如下图所示:
动态规划递归方程:
动态规划实现编码:
public int palindrome1(String str){
char chs[]=str.toCharArray();
int maxLen=0;
boolean f[i][j]=new boolean[chs.length][chs.length];
for(int j=0;j<str.length();j++)
{
f[j][j]=true;
//一个元素肯定是回文串。
for(int i=0;i<j;i++)
{
f[i][j]=(chs[j]==chs[i]&&(j-i<2||j>0&&f[i+1][j-1]));
//如果chs[j]==chs[i]当串的长度小于等于2时,肯定是回文子串,如 1,1,就是回文串。
//如果长度大于2时,则需要判断f[i+1][j-1]是不是回文。
if(f[i][j])
{
max_len=Math.max(max_len, j-i+1);
}
//max_len保存最大回文子串的长度。
}
}
return maxLen;
}