题目:5. 最长回文子串
解答:
class Solution {
public:
string longestPalindrome(string s) {
int n=1,maxlen=1;//定义回文串长度n,回文串最大长度maxlen
int res_left=0;//定义为找到的结果字符串的左端点
if(s.length()==1||s.length()==0) return s;
for(int i=0;i<s.length();i++){
int l=i-1,r=i+1;
n=1;
while(r<s.length()&&s[r]==s[i]){//向右扩散
r++;
n++;
}
while(l>=0&&r<s.length()&&s[l]==s[r]){//向左和向右同时扩散
l--;r++;
n+=2;
}
if(n>maxlen){//更新maxlen和起点res_left
maxlen=n;
res_left=++l;
}
}
string res;
for(int i=res_left;i<=res_left+maxlen-1;i++)
res.push_back(s[i]);//把找到的最长回文串放进结果数组中
return res;
}
};
方法:本题采用中心扩散法(看题解说是叫这个名儿)
1、采用一个大的for循环对字符串s从左到右遍历一次。
2、其中包含两个while循环,第一个处理当前遍历到的元素s[i]与s[r]相等的情况,实现”向右扩散“,第二个处理元素两侧s[l]与s[r]相等的情况,实现“向左向右同时扩散”。
误区:
此方法看起来简单易懂,但其实有很多重要的细节,比如让我们思考以下几个问题:
1、为什么这段代码中没有向左扩散的while循环呢?
2、向左向右扩散时,s[l]和s[r]一定是关于s[i]对称的吗?
3、这两个循环的顺序是否有严格要求?
问题一:我们从左至右遍历字符串s,并在每个位置都尝试向右扩散,比如当s为“a b b b”时,我们遍历到i=1时,便可以向右扩散从而找到“b b b”这个回文串,因此当i=2、3时,向左遍历是多余的。可见我们不需要向左遍历,也可以考虑到所有情况。
问题二:这是不一定的,很有可能首先向右扩散了。比如“a b b b b a c”,当i=1时,初始l=0、r=1,经过向右扩散后l=0、r=5,然后再向左向右扩散,比较的是s[0]与s[5],而这两个元素并不关于s[1]对称。
问题三:必须先向右扩散、再向左向右扩散。比如“b a b a c”,如果我们将两个while循环换了位置,当i=1时,首先向左向右扩散,跳出第一个while循环时l=-1、r=3,此时我们进入第二个while循环,比较s[i]与s[r],会发现相等,从而向右扩散,认为“b a b a”是一个回文串,很明显错误。因此两个循环的顺序不可以随意调换。
如果对您有帮助并且您方便的话,期待您可以打赏一下,感谢!