马拉车算法

求回文子串

LeetCode 647
思路参考这里

代码实现

class Solution {
public:
    // Manacher 模板
    int countSubstrings(string s) {
        // [STEP1] 修改源字符串
        // 将 s 改造为 t,这样就不需要讨论 s.length() 的奇偶性,因为新串 t 的每个回文子串都是奇回文串(都有回文中心)
        // s 和 t 的下标转换关系:
        // (si+1)*2 = ti
        // ti/2-1 = si
        // ti 为偶数,对应奇回文串(从 2 开始)
        // ti 为奇数,对应偶回文串(从 3 开始)
        string t = "^";
        for (char c : s) {
            t += '#';
            t += c;
        }
        t += "#$";

        // [STEP2] 计算回文半径
        // 定义一个奇回文串的回文半径=(长度+1)/2,即保留回文中心,去掉一侧后的剩余字符串的长度
        // half_len[i] 表示在 t 上的以 t[i] 为回文中心的最长回文子串的回文半径
        // 即 [i-half_len[i]+1,i+half_len[i]-1] 是 t 上的一个回文子串
        vector<int> half_len(t.length() - 2);
        half_len[1] = 1;

        int ans = 0;
        // box_r 表示当前右边界下标最大的回文子串的右边界下标+1
        // box_m 为该回文子串的中心位置,二者的关系为 r=mid+half_len[mid]
        int box_m = 0, box_r = 0;
        for (int i = 2; i < half_len.size(); i++) {
            int hl = 1;
            if (i < box_r) {
                // 记 i 关于 box_m 的对称位置 i'=box_m*2-i
                // 若以 i' 为中心的最长回文子串范围超出了以 box_m 为中心的回文串的范围(即 i+half_len[i'] >= box_r)
                // 则 half_len[i] 应先初始化为已知的回文半径 box_r-i,然后再继续暴力匹配
                // 否则 half_len[i] 与 half_len[i'] 相等
                hl = min(half_len[box_m * 2 - i], box_r - i);
            }

            // 暴力扩展
            // 算法的复杂度取决于这部分执行的次数
            // 由于扩展之后 box_r 必然会更新(右移),且扩展的的次数就是 box_r 右移的次数
            // 因此算法的复杂度 = O(t.length()) = O(n)
            while (t[i - hl] == t[i + hl]) {
                hl++;
                box_m = i;
                box_r = i + hl;
            }

            half_len[i] = hl;
            ans += hl / 2;
        }

        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值