[C++] LeetCode 5. 最长回文子串

题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

示例 2:
输入:"cbbd"
输出: "bb"

思路解析

这题求最长回文子串,有三种方法可以采用,最简单的是用动态规划,时间复杂度是O( n 2 ),另外一种是中心扩展,第三种方法是称为马拉车的算法。

方法一 动态规划

动态规划需要开一个二维数组,DP[i][j]=s[i]==s[j]&&DP[i+1][j-1],时间复杂度较高
代码:

class Solution {
public:
    string longestPalindrome(string s) {
        int len=s.size();
        vector<vector<int>> flag(len,vector<int>(len,0));
        int maxres=0,idx=0;
        for(int i=0;i<len;i++){
            for(int j=0,k=i;j<len&&k<len;j++,k++){
                if(k==j) flag[j][k]=1;
                else if(s[k]==s[j]&&j+1==k) flag[j][k]=2;
                else if(s[k]==s[j]&&flag[j+1][k-1]>0) flag[j][k]=flag[j+1][k-1]+2;
                else flag[j][k]=0;
                if(flag[j][k]>maxres){
                    maxres=flag[j][k];
                    idx=j;
                }
            }
        }
        return s.substr(idx,maxres);
    }
};

方法二 中心扩展

这种做法主要是考虑基于一个点为中心,然后左右两边扩展,得出以该点为中心的最长回文串。但是需要注意的是回文串长度是奇数和偶数,有所差别需要都考虑。
时间复杂度高于上一种方法
代码:

//加快代码运行速度
static const auto __ = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size(),pos=-1,maxlen=0;
        for(int i=0;i<n;i++){
            int r=1;
            while(i-r>=0&&i+r<n&&s[i-r]==s[i+r]) r++;
            if(maxlen<2*r-1){
                pos=i-r+1;
                maxlen=2*r-1;
            }
            if(i>=n||s[i]!=s[i+1]) continue;
            r=1;
            while(i-1>=0&&i+1+r<n&&s[i-r]==s[i+1+r]) r++;
            if(maxlen<2*r){
                pos=i-r+1;
                maxlen=2*r;
            }
        }
        return s.substr(pos,maxlen);
    }
};

方法三 马拉车算法

马拉车算法可以实现近似O(n)求解,具体原理见马拉车算法
代码:

//加快代码运行速度
static const auto __ = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
    string longestPalindrome(string s) {
        int pos=0,curlen=0,ns=s.size(),maxpos=0,maxr=0;
        //这里直接用tmp(2*ns+1,'*')指定tmp空间大小,防止超过tmp内存的时候扩充内存,导致溢出(在最短回文串中会起作用),同时可以减少代码运行时间
        string tmp(2*ns+1,'*');
        for(int i=0;i<ns;i++)
            tmp[2*i+1]=s[i];
        int n=tmp.size();
        vector<int> slen(n,0);
        for(int i=0;i<n;i++){
            int mi=2*pos-i,r=mi>=0?slen[mi]:0;
            if(i<pos+curlen&&i+r<pos+curlen){
                slen[i]=slen[mi];
                continue;
            }
            if(i>=pos+curlen) r=1;
            else r=pos+curlen-i;
            while(i+r<tmp.size()&&i-r>=0){
                if(tmp[i+r]==tmp[i-r]) r++;
                else break;
            }
            slen[i]=r-1;
            pos=i;
            curlen=r-1;
            if(maxr<=r-1){
                maxpos=i;
                maxr=r-1;
            }
            if(i+r==tmp.size()) break;
        }
        return s.substr(maxpos/2-maxr/2,maxr);
    }
};

猜你喜欢

转载自blog.csdn.net/lv1224/article/details/81051875