问题描述
给你一个字符串 s,找到 s 中最长的回文子串。
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
输入:s = “cbbd”
输出:“bb”
输入:s = “a”
输出:“a”
输入:s = “ac”
输出:“a”
一、解题思路
回文字符串的定义为:指定字符串从左向右输出与从右向左输出结果相同。最容易想到的解决方法是使用双重遍历,以字符串中的每个字符为子串起点,再从输入字符串中遍历子串的最后一个字符,对生成的子串进行判断(是否是回文)。伪代码如下所示:
max=0
result=Null;
for i in 字符串长度:
for j=i in 字符串长度:
字串=s.subString(i,j)
if(字串是回文&&字串长度>max)
max=字串的长度
result=字串
return result
判断回文的算法思想是使用左右指针分别指向待判断的字符串的开头和末尾,以两指针指向字符相同为循环判断条件,在结束循环之后判断右指针是否小于左指针,如果小则是回文。伪代码如下所示:
left=字符串起始位置
right=字符串结束位置
while(left<字符串长度&&right>=0&&left<=right&&s[left]==s[right])
left++;
right--;
if(left>right)
return true;
return false;
但是上述算法时间复杂度过高,所以引入中心扩展算法,遍历字符串,以字符为中心点,左指针向左移动,右指针向右移动,判断左右指针中间的字符串是否为回文。需要值得注意的是回文长度可能为奇数也可能为偶数,所以进行中心扩展的时候要分情况讨论。
二、JAVA 代码
public String longestPalindrome(String s){
int max=0;
String result=null;
if(s.length()>0) result=s.substring(0,1);
for (int i=0;i<s.length();i++){
int lenEven=centerExpand(s,i,i+1);
int lenOld=centerExpand(s,i,i);
if (lenEven<=max&&lenOld<=max) continue;
if (lenEven>lenOld){
max=lenEven;
result=s.substring(i-lenEven/2+1,i+lenEven/2+1);
}else {
max=lenOld;
result=s.substring(i-lenOld/2,i+lenOld/2+1);
}
}
return result;
}
public int centerExpand(String s,int left,int right){
while (left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)){
left--;
right++;
}
return right-left-1;
}
总结
对字符串和数组的操作要注意下标问题,使用JDK提供的substring()函数时,想要返回下标为0到10的字串参数应为substring(0,11).