Manacher算法,还有这些你不知道

如果想了解更多内容,欢迎关注我的微信公众号:信息学竞赛从入门到巅峰。

 

今天我们来介绍一下处理回文字符串的算法:Manacher(俗称“马拉车”)。

回文字符串的通俗定义是:如果一个字符串正着读或反着读都一样,那么称这个字符串为回文字符串。Manacher的作用就是在O(N)的时间复杂度下求出以每个位置为回文中心的回文半径。

接下来我们来看看Manacher算法的原理和实现方法吧。

我们还是采用动态规划的思想,假设0~i的位置的回文半径都求出来了,那么怎么求第i+1个位置的回文半径呢?考虑如果i+1这个位置在被之前覆盖范围最远的一个回文串包含(假设这个回文串的回文中心为j),那么i+1关于j对称的位置(不妨设为k)就可以转移到i+1这个位置,给i+1位置的回文半径一个初始的值。如果不被之前求过的任意字符串包含的话,那么显然为1(它自己)。

接下来我们要考虑是否i+1位置和k位置的差别。显然,i+1个位置可能还可以继续拓展,那么直接拓展即可(想想时间复杂度为什么是对的)。

我们把每个字符作为回文中心去处理,那么很显然对于长度为偶数的回文串无法得到很好的处理,怎么办呢?其实我们只要在每个字符中间加入一个该字符串没有的符号,并且在头尾加入没出现过的不同的符号就行了(如下面这个字符串)。

代码如下:

s[0] = '$'; s[++m] = '#';
for (b = 1; ss[b] != '\0'; ++b) {
    s[++m] = ss[b];
    s[++m] = '#';
}
s[++m] = '?';
for (int i = 1; i < m; ++i) {
    if (maxid > i) p[i] = min(maxid-i, p[2*id-i]);
    else p[i] = 1;
    while (s[i-p[i]] == s[i+p[i]]) p[i]++;
    if (i + p[i] > maxid) {
        maxid = i + p[i];
        id = i;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章