LeetCode——005

这里写图片描述

/*
5. Longest Palindromic Substring My Submissions QuestionEditorial 
Solution Total Accepted: 104198 Total Submissions: 453572 Difficulty: 
Medium Given a string S, find the longest palindromic substring in S.
You may assume that the maximum length of S is 1000, and there exists
one unique longest palindromic substring.

Subscribe to see which companies asked this question
*/

/*
思路一:使用二维动态规划(很可惜超时),引起超时的原因是使用了vector,如果使用a[][]则可通过
二维动态规划,时间复杂度为O(n2) 
dp[j][i]: 判断j~i之间是否是回文串
动态转移方程式: dp[j][i]=(s[i]==s[j] &&(i-j<2 || dp[j+1][i-1]))
解释:判断j~i是否是回文,条件1是s[i]==s[j],条件2是要么j到i之间少于两个字符,要么内层字符串为回文

*/
//思路一代码如下:
class Solution {
public:
    string longestPalindrome(string s) {

        //最长的回文子串
        //动态规划方法,也是判断串中回文的比较通用的方法

        //长度小于2,要么空,要么是回文串,直接返回
        if(s.size()<2)return s;
        //定义动态规划二维数组dp[j][i],即判断j~i之间是否是回文
        vector<vector<bool>> dp(s.size(),vector<bool>(s.size(),false));

        int start=0,len=0;
        for(int i=0;i<s.size();i++){
            dp[i][i]=true;
            for(int j=0;j<i;j++){

                dp[j][i]=(s[j]==s[i]&&(i-j<2 || dp[j+1][i-1]));
                if(dp[j][i]&& len<i-j+1){
                    len=i-j+1;
                    start=j;
                }
            }
        }

        return s.substr(start,len);
    }
};
//思路一修改数组:
class Solution {
public:
    string longestPalindrome(string s) {

        //最长的回文子串
        //动态规划方法,也是判断串中回文的比较通用的方法

        //长度小于2,要么空,要么是回文串,直接返回
        if(s.size()<2)return s;
        //定义动态规划二维数组dp[j][i],即判断j~i之间是否是回文
        bool dp[s.size()][s.size()]={0};

        int start=0,len=0;
        for(int i=0;i<s.size();i++){
            dp[i][i]=true;
            for(int j=0;j<i;j++){

                dp[j][i]=(s[j]==s[i]&&(i-j<2 || dp[j+1][i-1]));
                if(dp[j][i]&& len<i-j+1){
                    len=i-j+1;
                    start=j;
                }
            }
        }

        return s.substr(start,len);
    }
};
//思路二:马拉车算法
 [Manacher algorithm](http://www.cnblogs.com/grandyang/p/4475985.html)
/*最后要来的就是大名鼎鼎的马拉车算法Manacher's Algorithm,这个算法的神奇之处在于将时间复杂度提升到
了O(n)这种逆天的地步,而算法本身也设计的很巧妙,很值得我们掌握,参见我另一篇专门介绍马拉车算法的博
客Manacher's Algorithm 马拉车算法,代码实现如下:*/

//本题思路讲解:
/*
本算法只适用于求字符串中最长的的回文子串或者其长度,具体操作步骤如下:
1.先对字符串进行处理,因为字符串长度有奇有偶,所以首先要填充一些字符,使其变成恒奇字符串(或恒偶)
我们在每个字符的左右两侧加入‘#’,为了区分头部和尾部,在最前面在加上一个'$'。
2.添加一个对应新字符串的一个数组p[],p[i]代表以i字符为中心的回文串长度,赋初始值为0。另外添加一个
随时的中心点,以及以此点为中心的回文串最右侧的点mx,初始化都为0即id=0,mx=0;
为了得到我们想要的结果我们还要设两个变量来存储我们想要的结果resid,resmx;
3.开始遍历新数组i从0开始或者从1开始都行,对每个i值首先看看是不是能够利用上之前的记录即:
p[i]=mx>i? min(p[2*id-i],mx-i):1;  
//当mx>i时,是可以利用上的,即p[i]就不需要从1慢慢开始了
//当mx<=i时,利用不上,只能从1开始,慢慢搜索了

接下来就是继续在p[i]的基础上想外探索 while(t[i+p[i]]==t[i-p[i]])++p[i];

循环完后,以i为中心的回文就已经确定下来了,该更新中心点id 和半径mx了
当mx<i+p[i]时更新中心点为i,半径点mx=i+p[i]

一切搞定之后,我们看看是否当前i的回文串是不是符合我们结果的要求啊,即记录最大的中心点和半径

4.取得最后结果,我们已经有了中心点和半径,最终结果是先从新串中取出最长串然后去掉其中的‘#’
就得到了最终的结果。
我们可以一步到位,从已知新串的中心和半径直接去确定原串中的起始点和长度
即return s.substr((resId-resMx)/2,resMx-1);


*/
class Solution {
public:
    string longestPalindrome(string s) {
        string t ="$#";
        for (int i = 0; i < s.size(); ++i) {
            t += s[i];
            t += '#';
        }
        int p[t.size()] = {0}, id = 0, mx = 0, resId = 0, resMx = 0;
        for (int i = 0; i < t.size(); ++i) {
            p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
            while (t[i + p[i]] == t[i - p[i]]) ++p[i];
            if (mx < i + p[i]) {
                mx = i + p[i];
                id = i;
            }
            if (resMx < p[i]) {
                resMx = p[i];
                resId = i;
            }
        }
        return s.substr((resId - resMx) / 2, resMx - 1);
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值