LeetCode 5. 最长回文子串

题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

示例1

输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

实例2

输入: "cbbd"
输出: "bb"

思路

这道题最暴力的就是直接判断所有子串是否是回文串,然后选择最长长度的回文串作为结果输出。然而这样一点都不优雅,稍微思考一下,觉得可以从每个位置出发,依次向两边遍历,比较两边的字符是否一致,按这种方法来选择回文串。提交了一次后发现过不了,像“abbc”这种串,第一个字符b的两侧分别为a和c,按照前面的方法比较不符合回文性质;同理第二个字符b也一样。所以就发现一个问题,对于相邻且相同的字符应该特殊处理一下,可以将它们作为一个整体,每次比较的是这个整体两侧的字符。于是有以下代码:

class Solution {
public:
    string longestPalindrome(string s) {
        string res = "";
        for(int i = 0; i < s.length(); ){
            int len = 1, start=i-1,end=i+1;
            while(start>=0 && s[start] == s[i]) {
                start--;
                len++;
            }
            while(end<=(s.length()-1) && s[end] == s[i]){
                end++;
                len++;
            }
            while(start>=0 && end<=(s.length()-1)){
                if(s[start]==s[end]){
                    len+=2;
                    start--;end++;
                } else{
                  break;  
                }
            }
            if(len>res.length()){
                res = s.substr(start+1, end-start-1);
                cout << res << "\n";
            }
            i = temp;
        }
        return res;
    }
};

做是做出来了,就是时间太慢了。不妥,继续优化。
在这里插入图片描述

优化

由于前面已经将相邻的相同字符作为一个整体处理,那么对于这些字符,只需执行一次查找即可。在代码中添加两处改变:

class Solution {
public:
    string longestPalindrome(string s) {
        string res = "";
        for(int i = 0; i < s.length(); ){			// 不需要在for循环中执行 ++i 了
            int len = 1, start=i-1,end=i+1;
            while(start>=0 && s[start] == s[i]) {
                start--;
                len++;
            }
            while(end<=(s.length()-1) && s[end] == s[i]){
                end++;
                len++;
            }
            int temp = end;		// 保存最后一个相同字符的后一个位置,作为i的下一个值
            while(start>=0 && end<=(s.length()-1)){
                if(s[start]==s[end]){
                    len+=2;
                    start--;end++;
                } else{
                  break;  
                }
            }
            if(len>res.length()){
                res = s.substr(start+1, end-start-1);
                cout << res << "\n";
            }
            i = temp;
        }
        return res;
    }
};

效果显著,从36ms到8ms。

在这里插入图片描述

仔细再想想,既然已经作为一个整体了,在第一次遇到一个字符的时候会自动将后面紧接着的相同字符也加进入作为一个整体,那么根本不要往前面找相同字符了。也就是说,下面代码是多余的,注释掉即可。

            // while(start>=0 && s[start] == s[i]) {
            //     start--;
            //     len++;
            // }

最后的结果,4ms,心满意足。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值