5. 最长回文子串
问题描述:给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
解法1:中心扩展
思路:从每一个位置出发,向两边扩散即可。遇到不是回文的时候结束。举个例子,str=acdbbdaastr = acdbbdaastr=acdbbdaa 我们需要寻找从第一个 b(位置为 333)出发最长回文串为多少。怎么寻找?
首先往左寻找与当期位置相同的字符,直到遇到不相等为止。
然后往右寻找与当期位置相同的字符,直到遇到不相等为止。
最后左右双向扩散,直到左和右不相等。需注意记录窗体的长度,返回的是子串所以要更新最大回文子串的长度和起始位置;
代码实现:
public String longestPalindrome1(String s) {
if(s==null||s.length()==0){
return "";
}
int strlen = s.length();
int left =0;
int right =0;
// 滑动窗体大小
int len=1;
// 最长回文子串长度
int maxLen =0;
// 最长回文子串起始地址
int maxStart =0;
for (int i=0;i<strlen;i++){
left =i-1;
right =i+1;
while (left>=0 && s.charAt(left)==s.charAt(i)){
left--;
len++;
}
while (right<strlen && s.charAt(right)==s.charAt(i)){
right++;
len++;
}
while (left>=0&&right<strlen && s.charAt(right) == s.charAt(left)){
len= len+2;
left--;
right++;
}
// 更新回文子串数据
if(len>maxLen){
maxLen =len;
maxStart =left;
}
len =1;
}
return s.substring(maxStart+1,maxStart+maxLen+1);
}
2.动态规划
思路:时间换空间 新建dp数组 dp[l][r] = true代表是回文子串 false 表示不是
初始状态:dp[l][r] = true
转移方程:dp[l-1][r+1] =true 条件是l 和 r的字符相同
代码:
解法3:中心扩展改进
思路:在上述动态规划法中添加条件当剩余字符串小于最大回文串就不在判断,因为即使它是回文串也不是最大回文子串
搜索方式改为双向同时搜索,此时要先判断右边是否有重复字符,如果有就从下一个重复字符开始判断
代码实现:
public String longestPalindrome4(String s) {
int charLen = s.length();//源字符串的长度
int length = charLen * 2 + 1;//添加特殊字符之后的长度
char[] chars = s.toCharArray();//源字符串的字符数组
char[] res = new char[length];//添加特殊字符的字符数组
int index = 0;
//添加特殊字符
for (int i = 0; i < res.length; i++) {
res[i] = (i % 2) == 0 ? '#' : chars[index++];
}
//新建p数组 ,p[i]表示以res[i]为中心的回文串半径
int[] p = new int[length];
//maxRight(某个回文串延伸到的最右边下标)
//maxCenter(maxRight所属回文串中心下标),
//resCenter(记录遍历过的最大回文串中心下标)
//resLen(记录遍历过的最大回文半径)
int maxRight = 0, maxCenter = 0, resCenter = 0, resLen = 0;
//遍历字符数组res
for (int i = 0; i < length; i++) {
if (i < maxRight) {
//情况一,i没有超出范围[left,maxRight]
//2 * maxCenter - i其实就是j的位置,实际上是判断p[j]<maxRight - i
if (p[2 * maxCenter - i] < maxRight - i) {
//j的回文半径没有超出范围[left,maxRight],直接让p[i]=p[j]即可
p[i] = p[2 * maxCenter - i];
} else {
//情况二,j的回文半径已经超出了范围[left,maxRight],我们可以确定p[i]的最小值
//是maxRight - i,至于到底有多大,后面还需要在计算
p[i] = maxRight - i;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
}
} else {
//情况三,i超出了范围[left,maxRight],就没法利用之前的已知数据,而是要一个个判断了
p[i] = 1;
while (i - p[i] >= 0 && i + p[i] < length && res[i - p[i]] == res[i + p[i]])
p[i]++;
}
//匹配完之后,如果右边界i + p[i]超过maxRight,那么就更新maxRight和maxCenter
if (i + p[i] > maxRight) {
maxRight = i + p[i];
maxCenter = i;
}
//记录最长回文串的半径和中心位置
if (p[i] > resLen) {
resLen = p[i];
resCenter = i;
}
}
//计算最长回文串的长度和开始的位置
resLen = resLen - 1;
int start = (resCenter - resLen) >> 1;
//截取最长回文子串
return s.substring(start, start + resLen);
}
解法5:暴力破解
思路:略
代码实现:
public String longestPalindrome(String s) {
if (s.length() < 2)
return s;
int start = 0;
int maxLen = 0;
for (int i = 0; i < s.length() - 1; i++) {
for (int j = i; j < s.length(); j++) {
//截取所有子串,然后在逐个判断是否是回文的
if (isPalindrome(s, i, j)) {
if (maxLen < j - i + 1) {
start = i;
maxLen = j - i + 1;
}
}
}
}
return s.substring(start, start + maxLen);
}
//判断是否是回文串
private boolean isPalindrome(String s, int start, int end) {
while (start < end) {
if (s.charAt(start++) != s.charAt(end--))
return false;
}
return true;
}

浙公网安备 33010602011771号