214. 最短回文串

214. 最短回文串

题目描述

给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

示例 1:

输入:s = "aacecaaa"
输出:"aaacecaaa"

示例 2:

输入:s = "abcd"
输出:"dcbabcd"

提示:

  • 0 <= s.length <= 5 * 10^4
  • s 仅由小写英文字母组成

题解:

s 前面添加字符,将其变成回文串,本质就是求 s 的最长回文前缀。

比如 s = abcd,其最长回文前缀为 a ,将剩下的部分复制一份,即可得到 ret = dcbabcd

法一:

Manacher算法。

考虑 manacher 算法,其可线性求每个位置的最长回文子串,关于 manacher 算法,请看 最长回文子串

从右到左计算回文半径时,关注回文半径最左即将到达的位置,一旦发现已经到达字符串起始字符前一个位置,说明必须包含第一个字符的最长回文半径已经找到,直接退出即可。

时间复杂度: O ( n ) O(n) O(n)
额外空间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    string shortestPalindrome(string s) {
        string t = "";
        int len = s.size() * 2 + 1;
        for ( int i = 0, k = 0; i < len; ++i ) {
            if ( i & 1 ) t += s[k++];
            else t += '#';
        }
        vector<int> p(len);
        int r = len, c = len, ret = 0;
        for ( int i = len - 1; i >= 0; --i ) {
            p[i] = r < i ? min( i - r, p[2 * c - i] ) : 1;
            while ( i + p[i] < len && i >= p[i] ) {
                if ( t[i + p[i]] == t[i - p[i]] )
                    ++p[i];
                else break;
            }
            if ( i - p[i] < r ) {
                r = i - p[i];
                c = i;
            }
            if ( r == -1 ) {
                ret = p[i] - 1;
                break;
            }
        }
        t = "";
        for ( int i = s.size() - 1; i >= ret; --i )
            t += s[i];
        t += s;
        return t;
    }
};
/*
时间:4ms,击败:84.78%
内存:7.6MB,击败:52.17%
*/
法二:

KMP算法。

因为 kmp 算法中的 next[i] 表示以 i 为终点的后缀和从 1 开始的前缀相等,且后缀长度最长。

于是可以把 s 逆序 s' ,然后对 s + s'next 数组。注意,我们可以在 ss' 之间添加一个分隔符 # ,确保求得的前后缀不会超过 s 本身的长度。

时间复杂度: O ( n ) O(n) O(n)

额外空间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    string shortestPalindrome(string s) {
        string t( s.rbegin(), s.rend() );
        string p(' ' + s + '#' + t);
        int n = p.size() - 1;
        vector<int> next(n + 1);
        for ( int i = 2, j = 0; i <= n; ++i ) {
            while ( j && p[i] != p[j + 1] ) j = next[j];
            if ( p[i] == p[j + 1] ) ++j;
            next[i] = j;
        }
        return t.substr(0, s.size() - next[n]) + s;
    }
};
/*
时间:0ms,击败:100.00%
内存:7.8MB,击败:35.57%
*/
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值