manacher算法

和KMP一样,是个字符串算法,是个O(n)算法,同样也是个通过减少无意义匹配来降低复杂度的算法。
但哪里不一样呢?
哪儿都不一样。
解决的问题不一样,优化的方法和思路不一样,代码不一样,还有这个比KMP简单多了。
它解决的问题是这样的:给出一个字符串,求它以任意位置为中心的最长回文子串长度。这个任意位置可能是某个字符上(比如abcba中的c),也可能在两个字符中间(比如abba中间的两个b)。
暴力就是枚举每个位置并向两边扩展,复杂度 O(n2) O ( n 2 )
manacher算法利用回文串的性质进行优化:
首先对字符串进行预处理,我们再每两个字符中间和字符串两边各添加一个#,这样的话,像abba这样的字符串就变成了#a#b#b#a#,也就是说,所有的原来长度为偶数的回文子串都变成了奇数长度,这个回文串的中心也从原来的虚无变成现在的#。
其次,维护两个值mid, maxright,maxright代表从左往右扫的过程中遇到最靠右的回文串的最右边的位置,mid代表该回文串的中心。这有什么用呢?
假设我们当前要求以第i个字符为中心的最长回文串,r[i]为这个回文串向右扩展的长度,那么有mid < i <= maxright + 1(想一想,为什么),且所有r[j]已知(j < i)。
当i < maxright时,设j为i关于mid对称的位置,那么有 r[i]=min(maxrighti,r[j]) r [ i ] = m i n ( m a x r i g h t − i , r [ j ] ) (还是想一想,为什么),然后再向右边进行拓展,如果最右边已经超过了maxright,就更新maxright和mid。
当i >= maxright时,因为右边的一切都是未知的,所以直接去拓展然后更新就好了。

Code

#include <iostream>
#include <cstring>
#include <cstdio>

const int maxn = 1.1e7 + 7; //洛谷奇葩数据范围

using namespace std;

int ans;
char t[maxn];
char s[maxn << 1];
int r[maxn << 1];

inline void manacher(char *t, int *r)
{
    int n = strlen(t), mid = 0, maxr = 0;
    for (int i = 0; i < n; i++) s[i << 1] = '#', s[i << 1 | 1] = t[i]; //添井号,当然其他符号也可以
    s[n << 1] = '#';
    for (int i = 0; i <= n << 1; i++) {
        if (i < maxr) r[i] = min(r[(mid << 1) - i], maxr - i); //j就是mid * 2 - i
        while (i + r[i] + 1 <= n << 1 && ~(i - r[i] - 1) && s[i + r[i] + 1] == s[i - r[i] - 1]) r[i]++; //向右拓展
        ans = max(ans, r[i]);
        if (i + r[i] > maxr) { //更新
            mid = i;
            maxr = i + r[i];
        }
    }
}

int main(void)
{
    scanf("%s", t);
    manacher(t, r);
    cout << ans;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值