【字符串 manacher】洛谷_3805 manacher算法

题意

求一个字符串中最长回文串的长度。

思路

m a n a c h e r manacher manacher算法。

首先我们先在字符串空隙中插入符号,以便处理偶数长度的回文串。

h w i hw_i hwi为以 i i i为中心最多能往旁边扩展的长度, m a x r i g h t maxright maxright为当前匹配到的最右边的回文串。

枚举 1 ∼ n 1\sim n 1n,如果 i < m a x r i g h t i<maxright i<maxright且在 m i d mid mid右边,那么根据回文字符串的对称性,可以知道它的对称点 j j j h w j ≤ h w i hw_j \leq hw_i hwjhwi,我们就可以直接用 h w j hw_j hwj更新 h w i hw_i hwi,然后再扩展,要注意用 h w j hw_j hwj来更新 h w i hw_i hwi不能使 i + h w i i+hw_i i+hwi超过 m a x r i g h t maxright maxright,因为不一定满足对成性。

如果 i > m a x r i g h t i>maxright i>maxright就从 1 1 1开始来扩展。

如果扩展完后的位置 > m a x r i g h t >maxright >maxright,我们就可以更新它和 m i d mid mid

答案就为 m a x { h w i } − 1 max\{hw_i\}-1 max{hwi}1,因为一开始我们在字符串空隙中插入了符号,所以不用 ∗ 2 *2 2

代码

#include
#include
#include

int n, ans;
int hw[22000002];
char a[11000000], s[22000002];

void init() {
    scanf("%s", a);
    s[0] = s[1] = '#';
    n = strlen(a);
    for (int i = 0; i < n; i++) {
        s[i * 2 + 2] = a[i];
        s[i * 2 + 3] = '#';
    }
    n = n * 2 + 2;
    s[n] = 0;
}

void manacher() {
    int maxright = 0, mid;
    for (register int i = 1; i < n; i++) {
        if (i < maxright)
            hw[i] = std::min(hw[mid * 2 - i], maxright - i);
        else hw[i] = 1;
        for (; s[i + hw[i]] == s[i - hw[i]]; hw[i]++);//扩展
        if (hw[i] + i > maxright) {//更新
            maxright = hw[i] + i;
            mid = i;
        }
        ans = std::max(ans, hw[i]);
    }
}

int main() {
    init();
    manacher();
    printf("%d", ans - 1);
}

你可能感兴趣的:(字符串)