首页 > 其他分享 >【字符串】Manacher

【字符串】Manacher

时间:2024-04-07 12:00:17浏览次数:14  
标签:int Manacher 算法 len lrs MAXN 字符串 回文

Manacher算法的本质是计算以字符串中的“每个字符”和“每两个相邻字符之间的空隙”作为对称中心的最大回文串的长度。所以利用这个性质可以解决一系列与子串是否是回文串、子串有多少是回文串的问题。

namespace Manacher {
const int MAXN = 1.1e7;

int n;
char s[MAXN + 10];          // 1-index string
int len[2 * MAXN + 10];     // len[mid] means the longest extended length
// for every substr[l, r] that satisfies mid == l + r

void manacher (char *s) {
    n = strlen (s + 1);
    len[2] = 1;
    for (int i = 2, j = 0; i <= (n << 1); ++i) {
        int p = i >> 1, q = i - p;
        int r = ( (j + 1) >> 1) + len[j] - 1;
        len[i] = r < q ? 0 : min (r - q + 1, len[ (j << 1) - i]);
        while (p > len[i] - 1 && q + len[i] < n && s[p - len[i]] == s[q + len[i]])
            ++len[i];
        if (q + len[i] - 1 > r)
            j = i;
    }
}
}

using namespace Manacher;

心情复杂:过去这么多年都没有好好学习过这个算法,每次都是抄模板,终于碰壁了一次。

想理解上面的算法是怎么工作的,需要先理解朴素算法。这里的朴素算法是指用 \(O(n^2)\) 时间复杂度计算出字符串中每个对称中心的最长拓展长度。

朴素算法是分别处理长度为奇数和长度为偶数的字符串,如下:

const int MAXN = 1e6;

int n;
char s[MAXN + 10];          // 1-index string
int len[2 * MAXN + 10];     // len[lrs] means the longest extended length
// for every substr[l, r] that satisfies lrs == l + r

void bruteforce (char *s) {
    n = strlen (s + 1);
    for (int lrs = 2; lrs <= 2 * n; lrs += 2) {
        len[lrs] = 1;
        int lmid = lrs / 2, rmid = lrs - lmid;
        // lrs = 2, [1, 1]
        // lrs = 4, [2, 2] -> [1, 3]
        // lrs = 6, [3, 3] -> [2, 4] -> [1, 5]
        while (1 <= lmid - len[lrs] && rmid + len[lrs] <= n
                && s[lmid - len[lrs]] == s[rmid + len[lrs]]) {
            ++len[lrs];
        }
    }
    for (int lrs = 3; lrs <= 2 * n; lrs += 2) {
        len[lrs] = 0;
        int lmid = lrs / 2, rmid = lrs - lmid;
        // lrs = 3, [1, 2]
        // lrs = 5, [2, 3] -> [1, 4]
        // lrs = 7, [3, 4] -> [2, 5] -> [1, 6]
        while (1 <= lmid - len[lrs] && rmid + len[lrs] <= n
                && s[lmid - len[lrs]] == s[rmid + len[lrs]]) {
            ++len[lrs];
        }
    }
}

/**
Return the max length of palindrome substr[l, r] that satisfy l + r == lrs
*/
int max_length_palindrome (int lrs) {
    return 2 * len[lrs] - (lrs % 2 == 0);
}

bool is_palindrome (int l, int r) {
    int lrs = l + r;
    return max_length_palindrome (lrs) >= (r - l + 1);
}

然后观察发现其实他们大体上算法是可以合并化简的:

void bruteforce (char *s) {
    n = strlen (s + 1);
    for (int lrs = 2; lrs <= 2 * n; ++lrs) {
        len[lrs] = (lrs % 2 == 0);
        int lmid = lrs / 2, rmid = lrs - lmid;
        while (1 <= lmid - len[lrs] && rmid + len[lrs] <= n
                && s[lmid - len[lrs]] == s[rmid + len[lrs]]) {
            ++len[lrs];
        }
    }
}

其他可以替代的办法:字符串哈希、回文自动机、后缀数组

如果只是求最长回文串的长度和位置,而不包含“有多少个不同的回文子串”之类的信息的话,字符串哈希是可以用二分答案的长度然后枚举每个回文中心暴力判断的。

标签:int,Manacher,算法,len,lrs,MAXN,字符串,回文
From: https://www.cnblogs.com/purinliang/p/18118787

相关文章

  • aardio教程五) 写Python风格的aardio代码(字符串篇)
    前言熟悉一个新的语言最麻烦的就是需要了解一些库的使用,特别是基础库的使用。所以我想给aardio封装一个Python风格的库,Python里的基础库是什么方法名,aardio里也封装同样的方法名。这样就不需要单独去了解aardio里一些方法的使用细节,可以很方便的将Python代码改成aardio代码。......
  • C++基础——字符串(C语言和C++的字符串风格区别)
    C语言风格的字符串字符串通常是以字符数组或字符指针的形式表示的。字符串以空字符('\0')结尾!!!两种形式:(1)字符指针形式的字符串charstr[]="HelloC++";(2)字符数组形式的字符串char*ptr="HelloC++";C风格字符串的运算运算需要使用string函数,需要加入头文件<stri......
  • 调换任意字符串位置
    对任意字符串取反,就是首元素和尾元素依次调换,最关键就是要调换几次。先用(需要#inclide<string.h>头文件)strlen()获取字符数组的字符长度,再通过取中间数。例如字符长度为3,则需要循环3/2次,就是一次,只需将下标为0和下标为2的元素对换就可以了。互换过程:char c[3]={0};chart=c[......
  • 常用API(一):StringBuilder (用StringBuilder操作字符串效率更高比String) StringBuff
     packagecom.itheima.StringBuilder1;publicclassStringBuilder1{publicstaticvoidmain(String[]args){StringBuilders=newStringBuilder();StringBuilders1=newStringBuilder("pengsuoqun");//创建新字符串s1.append(1......
  • c语言字符串函数(strlen strcpy strcat strcmp等使用及模拟)
    在编程的过程中,我们经常要处理字符和字符串,为了方便操作字符和字符串,C语⾔标准库中提供了一系列库函数,接下来我们就学习一下这些函数。目录1、strlen的使用及模拟实现。2、strcpy的使用及模拟实现。3、strcat的使用及模拟实现。4、strcmp的使用及模拟实现。5、strncpy的......
  • ida数据提取技巧-利用LazyIDA插件实现一键提取无法识别的字符串
    首先具体介绍一下这个技巧的意思,因为标题可能没有说的很明白在使用ida逆向分析的过程中,会遇到某些密文、密钥之类的字符串,而这些字符串往往不全是由正常字符组成的,其中存在一些非常规字符,而一旦ida在识别字符串的过程识别到这种字符,就会认为该字符串到此已经结束(但我们知道,字......
  • 【C语言学习】之字符数组与字符串处理函数
    1.字符数组1.字符数组的初始化1.单字符形式chara[3]={'a','b','c'}                定义一个字符型一维数组,数组名a,三个下表变量a,b,ccharb[][3]={'a','b','c','d','e','f','g'}  ......
  • 疯狂Python讲义学习笔记——第2章变量和简单类型2.4字符串入门
    思维导图          字符串的意思是“一串字符”,比如"Hello,Python"是一个字符串,"Howdoyoudo?"也是一个字符串。Python要求字符串必须使用引号括起来,可使用单引号或双引号,只要两边的引号能配对即可。4.1字符串和转义字符        字符串的内容几乎可......
  • 删除字符串中间的*
    描述输入一个字符串,将串前和串后的保留,而将中间的删除。输入描述一个含*的字符串。输出描述删除了串中的*的字符串。用例输入1 ***ABC123**123*abc***********用例输出1 ***ABC123123abc***********代码#include<bits/stdc++.h>usingnamespacestd;intmain(......
  • 黑马程序员Java从入门到起飞(上) P103 字符串-08-较难练习练习-金额转换
    文章目录标题:黑马程序员Java从入门到起飞(上)P103字符串-08-较难练习练习-金额转换前言一、案例的使用场景是什么?二、输入输出情况三、思路四、什么是查表法?五、代码实现六、完整代码总结标题:黑马程序员Java从入门到起飞(上)P103字符串-08-较难练习练习-金额转......