manacher算法代码的理解

1链接和代码

https://cp-algorithms.com/string/manacher.html

vector<int> manacher_odd(string s) {
    int n = s.size();
    s = "$" + s + "^";
    vector<int> p(n + 2);
    int l = 0, r = -1;
    for(int i = 1; i <= n; i++) {
        p[i] = max(0, min(r - i, p[l + (r - i)]));
        while(s[i - p[i]] == s[i + p[i]]) {
            p[i]++;
        }
        if(i + p[i] > r) {
            l = i - p[i], r = i + p[i];
        }
    }
    return vector<int>(begin(p) + 1, end(p) - 1);
}

2 相关说明

  • 这里虽然函数名称含有odd这一词语,但是并不是说只适用于寻找字符串中所有长度为奇数的回文字符串,不然这个函数的应用就太受限了。个人理解是:该算法的思路是基于长度为奇数的回文字符串产生的,但是实际上长度为偶数的回文字符串也同样适用,不妨这么理解,偶数回文字符串中间两个字符间存在一个隐藏的中间字符,但是这个字符是否显式存在不重要。(如果读者有其他理解,欢迎讨论)
  • 代码中巧妙地在字符串的开头和结尾补上了两个无关字符,即非数字非英文字母,这样做可以避免对左右边界的判断。可能读者会问了,只要回文字符串的左右边界不断向两边延伸,即使不会碰到原始字符串的边界,但还是会碰到"$“和”^",难道不会进一步越界?对,不会,因为到这两个边界的时候,必然会因为不匹配就退出了
  • 初始化时这里还可以设置为l=0,r=1,这对结果没有影响
  • 特别注重对max(0, min(r - i, p[l + (r - i)]))的理解,给定链接已经说明需要分两种情况,第一种就是r>=i的情形,这种情况下最直观的结果是r-i>=0, l+(r-i)>=l ,但是还有一层隐藏的关系在里面,这时候的i一定是【l, r】区域的中间值(l+r)/2的右侧位置, l+(r-i)一定在中间值(l+r)/2的左侧位置。这是因为如果i刚好等于这个回文字符串中间值的时候,l和r的值必然是在此时发生更新的,所以当i小于中间值的时候,这个时候的l和r还不是现在我们考虑的这种情形中的值。 r-i是限制当前的回文字符串半径长度不能超出当前的范围(存在大于r的值也属于以i为中心的回文字符串);而p【l+(r-i)】则是当前【l, r】区域中与i位置相对称的位置为回文字符串中心时的回文串最大长度,这个在前面的遍历过程中已经被计算出来了,这限制了以位置i为回文串中心的回文串最大长度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值