Leetcode214--最短回文串题解(KMP算法和Manacher算法)

原题链接:https://leetcode-cn.com/problems/shortest-palindrome/

很显然的,这道题可以转化为求最长前缀回文子串的问题。得到该子串后,只需要将字符串s的剩余部分翻转并拼接到s的最前面即可得最短回文串。

接下来我们尝试用两种方法来解决这个问题。

方法1:KMP算法

设s中的最长前缀回文子串为s1,将s进行翻转得到s’,则s1’为s’的最长后缀回文子串。由回文串的性质可知s1 = s1’。

将s作为模式串,s’作为目标串进行匹配。当遍历到s’的末尾时,如果匹配到s中的第i个字符,说明s的最长前缀回文子串的长度为i。

KMP算法详解
https://blog.csdn.net/qq_37969433/article/details/82947411

AC代码如下

class Solution {
public:
    string shortestPalindrome(string s) {

        int len = s.size();
        int next[len + 1];

        int i = 0, j = -1;
        next[0] = -1;
        while(i < len)
        {
            if(j == -1 || s[i] == s[j])
                next[++i] = ++j;
            else
                j = next[j];
        }

        string str = s;
        reverse(s.begin(), s.end());
        i = 0, j = 0;
        while(j < len)
        {
            if(str[i] == s[j])
            {
                i++;
                j++;
            }
            else
            {
                if(next[i] == -1)
                {
                    i = 0;
                    j++;
                }
                else
                {
                    i = next[i];
                }
            }
        }
        return s.substr(0, len - i) + str;
    }
};

方法2:Manacher算法

Manacher是用于求最长回文子串的一种高效的算法,时间复杂度为O(n)。

Manacher算法的模板中加入一条判断语句(判断回文子串的左端点是否为字符串s的左端点这一条件)即可解决该题。

Manacher算法详解
https://blog.csdn.net/dyx404514/article/details/42061017?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param

AC代码如下

class Solution {
public:
    string shortestPalindrome(string s) {

        int len = s.size();
        char tmp[2*len+4];
        int Len[2*len+4];
        tmp[0] = '@';
        for(int i = 1; i <= 2*len; i+=2)
        {
            tmp[i] = '#';
            tmp[i+1] = s[i/2];
        }
        tmp[2*len+1] = '#';
        tmp[2*len+2] = '$';

        int mx = 0, ans = 0, po = 0;
        for(int i = 1; i <= 2*len+1; i++)
        {
            if(i < mx)
            {
                Len[i] = min(mx-i, Len[2*po-i]);
            } 
            else
            {
                Len[i] = 1;
            }
            while(tmp[i-Len[i]] == tmp[i+Len[i]])
            {
                Len[i]++;
            }
            if(Len[i] + i > mx)
            {
                mx = Len[i]+i;
                po = i;
            }
            if(i == Len[i] && Len[i] - 1 > ans)
            {
                ans = Len[i] - 1;
            }
        }
        string str = s;
        reverse(s.begin(), s.end());
        return s.substr(0, len-ans) + str;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值