题目分析:回文子串就是将字符串反序后与原字符串相等,如:abccba或abcdcba,但是abcd就不算是回文字符串。就和我们熟知的回文数字一样,回文数字的判断十分简单,只需要循环取余相加就可以判断,但是字符串始终不是数字,所以就需要找到另一种方法来进行回文判断。
核心思路:所有的回文字符串都是关于中心对称的,所以我们可以先找到整个回文字符串的中心,再向两边进行扩展就可以计算得到整个回文字符串了。还有就是如何得到最大的回文字符串,如果我们先定义一个空的字符串每次都将得到的新的回文字符串进行存储再和旧的回文字符串进行大小比较会十分的麻烦,我们这里就可以采用双指针的方法,每次只需要记录回文字符串的起始索引位置和结束索引位置,就可以根据索引得到回文字符串的大小,在和上一个回文字符串的大小进行比较后对指针进行更新就行了。下面是代码书写过程
首先是对回文字符串中心的寻找,这里分两种情况,1.回文中心在其中一个字母上例如abcdcab。2.回文中心在两个字母中间,例如:abccba。所以我们就需要写两个判断条件一个是
if(temp[i]==temp[i-1])
另一个是
if(i-1>=0&&i+1<temp.length&&temp[i+1]==temp[i-1])
由于我们是从第二个字符开始进行判断的,所以第一个条件判断我们并不需要考虑是否越界,但是第二个条件就需要进行越界的考虑了。在这两个条件判断的基础上我们还要注意对索引位置进行更新,每次判断得到新的回文字符串长度大于旧的回文字符串时,就要对索引进行更新,而在进行中心扩展时我们还需要注意双指针不要越界且双指针且双指针位置的两个字符必须相等。下面是这部分的代码:
int answerBegin=0,answerEnd=0,begin,end,count=0,max=0;//记录最长回文子串的位置和字
符字串的长度和最长字符字串的长度
char[] temp=s.toCharArray();//将字符串转换成字符数组
for(int i=1;i<temp.length;i++)
{
if(temp[i]==temp[i-1])
{
begin=i-1;
end=i;
count=2;//记录新的回文字符串的大小
if(i+1<temp.length&&i-2>=0)//越界判断
{
for(int j=i+1,k=i-2;j<temp.length&&k>=0;j++,k--)//循环判断,指针不要越界
{
if(temp[j]==temp[k])
{
count+=2;
begin=k;
end=j;
}//双指针位置的字符是否相等
else
{
break;
}//不相等停止循环
}
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}//新的回文字符串和旧的回文字符串的大小比较,符合条件对指针进行更新
}
else
{
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}//新的回文字符串和旧的回文字符串的大小比较,符合条件对指针进行更新
}
}
count=0;
if(i-1>=0&&i+1<temp.length&&temp[i+1]==temp[i-1])//第二种情况的回文字符串
{
count+=3;
begin=i-1;
end=i+1;
if(i+1<temp.length&&i-1>=0)//越界判断
{
for(int j=i+2,k=i-2;j<temp.length&&k>=0;j++,k--)//越界判断
{
if(temp[j]==temp[k])//字符相等
{
count+=2;
begin=k;
end=j;
}
else
{
break;
}
}
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}//指针更新
}
else
{
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}
}
}
count=0;//count重置为0
}
这里有一个细节就是两个判断条件不能采用if-else if进行判断,必须使用if-if将两个条件进行并列判断,因为存在一种特殊情况就是既属于回文中心在字母上和回文中心不再字母上,就是所有字符都是相等的这种情况,如:ccccc,aaaaaa。这种就需要两种情况都进行判断。
最后经过上面的循环后我们就可以根据最终双指针停止的位置在通过循环遍历就可以得到最长的回文字符串了。下面是得到最长回文字符串的代码部分
String answer=new String();
for(;answerBegin<=answerEnd;answerBegin++)
{
answer+=temp[answerBegin];
}//对最终标记的索引位置进行遍历得到最终字符串
下面是整体代码:
class Solution
{
public String longestPalindrome(String s)
{
int answerBegin=0,answerEnd=0,begin,end,count=0,max=0;//记录最长回文子串的位置和字符字串的长度和最长字符字串的长度
char[] temp=s.toCharArray();//将字符串转换成字符数组
for(int i=1;i<temp.length;i++)
{
if(temp[i]==temp[i-1])
{
begin=i-1;
end=i;
count=2;//记录新的回文字符串的大小
if(i+1<temp.length&&i-2>=0)//越界判断
{
for(int j=i+1,k=i-2;j<temp.length&&k>=0;j++,k--)//循环判断,指针不要越界
{
if(temp[j]==temp[k])
{
count+=2;
begin=k;
end=j;
}//双指针位置的字符是否相等
else
{
break;
}//不相等停止循环
}
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}//新的回文字符串和旧的回文字符串的大小比较,符合条件对指针进行更新
}
else
{
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}//新的回文字符串和旧的回文字符串的大小比较,符合条件对指针进行更新
}
}
count=0;
if(i-1>=0&&i+1<temp.length&&temp[i+1]==temp[i-1])//第二种情况的回文字符串
{
count+=3;
begin=i-1;
end=i+1;
if(i+1<temp.length&&i-1>=0)//越界判断
{
for(int j=i+2,k=i-2;j<temp.length&&k>=0;j++,k--)//越界判断
{
if(temp[j]==temp[k])//字符相等
{
count+=2;
begin=k;
end=j;
}
else
{
break;
}
}
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}//指针更新
}
else
{
if(max<count)
{
max=count;
answerBegin=begin;
answerEnd=end;
}
}
}
count=0;//count重置为0
}
String answer=new String();
for(;answerBegin<=answerEnd;answerBegin++)
{
answer+=temp[answerBegin];
}//对最终标记的索引位置进行遍历得到最终字符串
return answer;
}
}
在这里我是将字符串转换成字符数组后再进行的后续的操作的,其实这里并不需要进行这一步的转换,可以直接使用charAt()得到字符串中指定位置的字符。
public char charAt(int index)
最后一步得到标记位置的字符串也可以使用subString()方法。
public String substring(int beginIndex, int endIndex)
//从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex。