【字符串处理】最长回文子串笔记(Manacher算法)

1.预处理部分

在每个字符之间及其两边插入一个分隔符,使得字符串形成一个新串。—>解决奇偶问题
注意:最终形成的字符串的两端必须是未出现过的不同的字符
例如 : %#a#b#c#d#e#$(特点:每个子串两端都有分隔符,注意两端,最前最后的字符不等)

2.用辅助数组长度

用一个辅助数组P记录以每个字符为中心的最长回文串的信息。P[id]记录的是以字符str[id]为中心的最长回文串,当以str[id]为第一个字符,这个最长回文串向右延伸了P[id]个字符。

     int mx = 0, id, maxlen = 0;
    for(int i = 1 ; i < len; i++)
    {
        p[i] = mx > i ? min(p[2*id-i], mx-i) : 1;
        for(; str[i + p[i]] == str[i - p[i]]; p[i]++);
        if( p[i] + i > mx ){ mx = p[i] + i; id = i;}
        if( p[i] > maxlen ) maxlen = p[i];
    }
    cout << maxlen - 1 << endl;

3.对代码的详解

其中mx记录的是前面回文串中的最右端,maxlen是当前所有回文串的最长值,id指前面回文串中拥有当前最右端的中心点。

p[i] = mx > i ? min(p[2*id-i], mx-i) : 1
/*这一段为核心部分
其中p[i]为当前位置的回文串长度,如果其包含在一个回文串中,也就是前面所说的拥有最右端的回文串中,则其关于id的对称点的回文串长度和当前点的回文串长度应该是相同的。如果其回文串长度加上其所在点仍然没有超过最右端,则其长度就是那么长,如果超过了就先以边界为长度,开始扩展。
*/

后面的代码都比较简单,中心就是利用回文串的特点尽量减少重复统计的次数。代码复杂度理论值是O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值