5 最长回文子串 dp & 马拉车

dp

dp[ i ][ j ]代表从i开始到j结束的字符串是否是回文的。
状态转移dp[ i ][ j ] = dp[ i +1][ j - 1 ] && s[i]==s[j]。
时间复杂度O(N*N)

class Solution {
public:
    string longestPalindrome(string s) {
        if(s.size()==0) return s;
        int dp[1005][1005];
        memset(dp,0,sizeof(dp));
        int len = s.size();
        for(int i=1;i<=len;++i) dp[i][i]=1;
        for(int i=1;i<len;++i) dp[i][i+1] = s[i]==s[i-1];
        for(int k=len-2;k>=1;--k){
            int i=1,j=len+1-k;
            for(int t=0;t<k;++t){
                dp[i][j] = dp[i+1][j-1]&&(s[i-1]==s[j-1]);
                ++i,++j;
            }
        }
        int ans=0,st;
        for(int i=1;i<=len;++i){
            for(int j=i;j<=len;++j){
                if(dp[i][j] && ans<j-i+1){
                    ans = j-i+1;
                    st=i;
                }

            }
        }
        return s.substr(st-1,ans);
    }
};

马拉车 Manacher
用数组r记录以字符串以每个字符为中心的回文串的半径。(仅考虑奇回文)aba就是010。
从0到n-1,遍历,记录当前最靠右的回文串的右边位置为R,对应回文串的中心位置为C。
现在要得到位置为i的字符的r[i],普通的方法就是让r[i]从0开始慢慢增大直到两边不对称。但可以考虑i之前的结果对i的影响:如果i在C和R之间,那么2C-i(C-(i-C))和i是对称的,如果2C-i的回文串半径小于R-i的话,那么r[i] = r[2C-i],不然r[i]>=R-i。如果是上述情况的第二种,r[i] 只要从R-i开始慢慢增大就可以了。由于R是只增不减的,所以最终时间复杂度为O(N)。
上面的方法只能考虑奇回文,马拉车算法通过在每个字符之间加入‘#’,把奇回文和偶回文都变成了技回文,aba就变成了#a#b#a#,r[i]就是整个回文串的答案。

class Solution {
public:
    string longestPalindrome(string s) {
       string s2 = "#",ans;
       for(auto &c:s) s2+=c,s2+='#';
       vector<int> r(s2.size(),0);
       int maxr(0),maxi(0);
       int C(0),R(0);
       for(int i=0;i<s2.size();++i){
           if(i<R) r[i] = min(R-i,r[C*2-i]);
           while(i-r[i]-1>=0 && i+r[i]+1<s2.size() && s2[i-r[i]-1]==s2[i+r[i]+1]) ++r[i];
           if(r[i]+i>R) R=r[i]+i, C=i;
           if(r[i]>maxr) maxr=r[i],maxi=i;
       }
       for(int i=maxi-maxr;i<=maxi+maxr;++i){
           if(s2[i]!='#') ans.push_back(s2[i]);
       }
       return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值