给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
-
1 <= s.length <= 1000
-
s 仅由数字和英文字母组成
思路:遇到这题,第一想法就是暴力求解。如下代码所示,枚举所有的子串,利用回文“反序与正序相同”的特性,判断是否回文。记录下最长的回文,并返回。当然,这种方法最终超时了。
class Solution {
public:
string longestPalindrome(string s) {
int maxstrlen=0;//最长回文子串长度
string maxstring;//最长回文子串
for(int i=0;i<s.size();i++)
{
for(int j=1;j<s.size()-i+1;j++)
{
int strlen=0;//回文子串长度
string tempstr=s.substr(i,j);
string fanzhuan=tempstr;
reverse(fanzhuan.begin(),fanzhuan.end());
if(fanzhuan==tempstr)
{
strlen=tempstr.size();
if(maxstrlen<strlen)
{maxstring = tempstr;maxstrlen=strlen;}
}
}
}
return maxstring;
}
};
以下方法采用中心扩散的方法。
如下图所示,对于已经是回文子串的s来说,同时向两边扩散,判断s的前一个与后一个字符是否相同。如相同,则扩散后的子串仍是回文串。若不同,则扩散后的子串不是回文串。
但是,该方法对于如下图所示的初始子串来说,肯定是不行的。因为只判断两边扩散的方法只会判定{b,b,a}是非回文。而忽略掉{b,b}子串。
所以需要对中心i向左或者向右扩散,找到重复的字符,加入回文子串,以防上述情况发生。
但是单边扩散仅限于回文中心位置。因为回文中心是重复字符的话,该中心必定符合回文性质。但是重复字符出现在回文非中心位置,则难以确认。
所以,以i为中心时,首先分别进行左右扩散,再进行中心扩散。详细如下所述。
首先,向左扩散找到相同的字符,并加入到回文子串中。直到遇到不相同的字符。
然后,向右扩散找到相同的字符,并加入到回文子串中。直到遇到不相同的字符。
最后,向左右两边同时扩散,找到两边对称的字符,双双加入回文子串中,直到两边字符不相称。
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();//n为字符串长度
int maxlen=0;
int maxstr=0;//最长回文子串的起始位置
for(int i=0;i<n;i++)
{
int left=i-1;
int right=i+1;
int len=1;//以i为中心扩散时的子串长度
while(left>=0&&s[left]==s[i]) {left--;len++;}//向左扩散
while(right<=n-1&&s[right]==s[i]) {right++;len++;}//向右扩散
while(left>=0&&right<=n-1&&s[left]==s[right])//向两边同时扩散
{left--;right++;len+=2;}
if(maxlen<len)
{maxlen=len;maxstr=left+1;}
}
string maxstring;
maxstring=s.substr(maxstr,maxlen);
return maxstring;
}
};