Manacher算法求解最长回文字符串,KMP算法求解匹配字符串


求解回文字符串时,可以通过暴力匹配法进行匹配,即每次移动一个字符,使用中心扩展法,计算最长回文字符串。这种匹配方式时O(n^2)复杂度。
Manacher算法可以以O(n)复杂度计算最长回文字符串。

一、Manacher算法流程

1.字符串扩充

由于字符串长度可能时偶数,可能时奇数,所以需要先对其进行统一。
Manacher的做法是:将任意字符间以及字符串开头和结尾增添一个标记字符,使得字符串长度都为奇数
比如
字符串为"abcdf"
扩充后的字符串为:“#a#b#c#d#f#”

2.回文字符串半径求解

回文半径数组radius是用来记录以每个位置的字符为回文中心求出的回文半径长度,如下图所示,对于p1所指的位置radius[6]的回文半径是5,每个位置的回文半径组成的数组就是回文数组,所以#a#c#b#b#c#b#d#s#的回文半径数组为[1, 2, 1, 2, 1, 2, 5, 2, 1, 4, 1, 2, 1, 2, 1, 2, 1]。

3.最右回文右边界R求解

一个位置最右回文右边界指的是这个位置及之前的位置的回文子串,所到达的最右边的地方。比如对于字符串#a#c#b#b#c#b#d#s#,求它的每个位置的过程如下:
也就是说字符串中下标i对应的最右回文右边界为前i个字符所能获得的右边界的最大值
在这里插入图片描述

4.最右回文右边界的对称中心C

就是上面提到的最右回文右边界的中心点C,如下图,p=4时,R=6,C=3
在这里插入图片描述

5.Manacher算法流程

图中:
1)MLC数组是以下标i为回文中心,能得到的回文字符串的最长半径
2)before数组是未扩充时的下标和对应元素
3)after数组时扩充后的字符串下标和对应元素
4)POS表示的是下标。POS(before)表示的是before数组中下标,同理POS(after)是扩充后的下标
5)START是回文字符串的起点
6)END是回文字符串终点
在这里插入图片描述

在这里插入图片描述

6.Manacher算法代码

class Solution {
public:
    int countSubstrings(string s) {
        int n = s.size();
        string t = "$#";
        for (const char &c: s) {
            t += c;
            t += '#';
        }
        n = t.size();
        t += '!';

        auto f = vector <int> (n);
        int iMax = 0, rMax = 0, ans = 0;
        for (int i = 1; i < n; ++i) {
            // 初始化 f[i]
            f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1;
            // 中心拓展
            while (t[i + f[i]] == t[i - f[i]]) ++f[i];
            // 动态维护 iMax 和 rMax
            if (i + f[i] - 1 > rMax) {
                iMax = i;
                rMax = i + f[i] - 1;
            }
            // 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
            ans += (f[i] / 2);
        }

二、KMP算法流程

KMP是用于进行字符串匹配的
下面的链接讲的比较详细,就不抄录
https://zhuanlan.zhihu.com/p/83334559

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值