Manacher算法

Manacher算法解决的问题:

字符串str中,最长回文子串的长度如何求解?

如何做到时间复杂度O(N)完成?

经典解法:时间复杂度O(N^2)

Manacher算法的解法与经典解法相似,但是有加速。

使用特殊字符扩充字符串,如"1221"扩充为"#1#2#2#1#",这样方便找字符个数为偶数的回文子串

特殊字符可以为任意字符,不会与字符串字符混淆,因为以任意字符为中心,比较左右两边字符时,总是实字符跟实字符比较,虚字符跟虚字符比较。

回文半径和回文直径:

"#a#1#2#1#b#",字符‘2’的回文半径是4,回文直径是7。

回文半径数组:

在从左往右遍历字符串时,把每个字符的回文半径记录下来

之前扩的所有位置中所到达的最右回文右边界R:初始值-1,向右只增不减

取得最右回文右边界时的中心点C:与R伴生

从左往右遍历时:

1)当前中心点不在最右回文右边界里:暴力扩

2)当前中心点在最右回文右边界内:

(1)i ' 的回文区域彻底在 (L ~ R) 里面   i 的回文半径 = i ' 的回文半径

(2)i ' 的回文区域在 [L , R] 外面  i 的回文半径 = R - i + 1

(3)i ' 的回文区域跟L压线   i 的回文半径 = R - i + 1,然后试着往外扩

时间复杂度:O(N)

string manacherString(string& s){
    int n = s.size();
    string str (2 * n + 1, '#');
    for(int i = 0; i < n; i++){
        str[2 * i + 1] = s[i];
    }
    return str;
}

int manacher(string& s){
    if(s.empty()){
        return 0;
    }
    string str = manacherString(s);
    vector<int> arr (str.size(), -1);
    int C = -1; // 中心
    int R = -1; // 回文右边界
    int res = INT_MIN;
    for(int i = 0; i < str.size(); i++){
        arr[i] = i < R ? min<int>(R - i + 1, arr[2 * C - i]) : 1;
        while(i - arr[i] >=0 && i + arr[i] < str.size()){
            if(str[i - arr[i]] == str[i + arr[i]]){
                arr[i]++;
            }
            else{
                break;
            }
        }
        if( i + arr[i] - 1 > R){
            R = i + arr[i] - 1;
            C = i;
        }
        res = max<int>(res, arr[i]);
    }
    return res - 1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芜湖高学成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值