Manacher算法,别称马拉车

题目:怎么找出一个字符串中回文的最长大小

ABAKK 最长回文为ABA,长度为3;abaaab最长回文为baaab,长度为5

代码

int len = str.length();
char* char_list = new char[len*2 + 1];
int * num_list = new int[len*2+1];
char_list[0] = '$';
int index = 0;
for(int i=1; i < len * 2 + 1; i++)
{
    char_list[i] = (i % 2 == 1)? str[index++] : '#';
}
// right_edge, curr_
int right_edge = -1;
int cur_center = -1;
int max_len = 0;

for(int i = 0; i < len * 2 + 1; i++)
{
    num_list[i] = (right_edge > i) ? min(num_list[2*cur_center - i], right_edge - i): 1;
    
    while(char_list[i + num_list[i]] == char_list[i - num_list[i]])
        num_list[i]++;
    
    if(right_edge < i + num_list[i])
    {
        right_edge = num_list[i] + i;
        cur_center = i;
    }
    
    if(max_len < num_list[i])
    {
        max_len = num_list[i];
    }
}

delete[] char_list;
delete[] num_list;
cout << max_len -1 << "\n";

算法解读

马拉车算法的核心思想是利用已有的匹配对算法进行加速,关键点在于cur_center、right_edge两个变量的使用,其中
right_edge: 表示当前匹配的已cur_center为中心点的最右边界(算法从左向右匹配),即以cur_center为中心点的区间【2cur_center - right_edge, right_edge】为一个回文字符串。
记录这两个点的好处在于,当遍历下标值i < right_edge时,我们可以知道,此时的i点存在回文,(原因是i在上述区间【2
cur_center - right_edge, right_edge】中,i的回文长度半径要么与它基于cur_center的对称点一致,要么为i到right_edge的距离,取决于哪个比较小),不理解的看图
在这里插入图片描述
如图所示,i相对于cur_center的对称点,画一个回文圈圈,由于对称原因,i点也有这么一个圈圈,如果这个圈圈没超出对称范围,则两边圈圈半径是一致的;如果这个圈圈超出了对称范围,那么i的圈圈只能半径只能在对称范围以内。
陈述上面这些主要是要理清马拉车的加速核心,就是直接利用已有的匹配(i的对称点的圈圈范围,跳过部分比较),剩下的只能用暴力比较法了。

算法其他

这个算法一开始用$、#这些符号插入到原字符串中,其一个作用主要是讲所有存在的奇、偶回文都变成奇回文,如AA => A#A 或 #A#A#,ABA=> A#B#A 或 #A#B#A#,方便处理。其他的作用我暂时没想到,有知道的朋友可以留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值