Manacher算法求最大回文串

Manacher 算法是用来求最长回文子串的算法
时间复杂度:O(n)
空间复杂度:O(n)

class Solution {
public:
    int getLongestPalindrome(string A, int n) {
        // write code here
        string s = "$#";
        for (const char& ch : A)
        {
            s += ch;
            s += '#';
        }
        int len = s.size();
        s += '!';
        int imax = 0;
        int rmax = 0;
        vector<int> f(len);
        for (int i = 1; i < len; ++i)
        {
            //初始化
            f[i] = (i <= rmax) ? min(rmax - i + 1, f[2 * imax - i]) : 1;
            //中心扩展
            while (s[i + f[i]] == s[i - f[i]]) ++f[i];
            //更新
            if (f[i] > rmax - imax + 1)
            {
                imax = i;
                rmax = i + f[i] - 1;
            }
        }

        return f[imax]-1;  //最长回文子串长度
    }
};
void Manacher(string s) 
    {
        //改造原字符串,如:asa变成$#a#s#a#!,assa变成$#a#s#s#a#!
        string t = "$#";
        for (const char &c : s) {
            t += c;
            t += '#';
        }
        int len = t.length(); 
        t += '!';
        auto f = vector<int>(len); 
        //对于第一个$和最后一个!,可以不计算以其为中心的最大回文子串 
        int iMax = 0;  //最大回文子串回文中心 
        int rMax = 0;  //最大回文子串右端点  

        for (int i = 1; i < len; ++i)  //计算以i为中心的最大回文子串 
        {
            // 初始化 f[i]:以i为中心的最大回文子串半径,i点也包括在内
            //f[2 * iMax - i] = f[iMax - (i - iMax)] = f[i对位],如果对位的f[i]没有超出最大回文串边界(左边界)则f[i]=f[i对位]成立,如1234321倒数第二位的2的f[i]等于顺数第二位的2的f[i]
            //如果对位的f[i]超出了最大回文串边界(左边界),则本位的f[i]是从rMax-i+1开始中心增大的,如31234321倒数第二位的2的f[i]不等于顺数第第三位的2的f[i],而是为rMax-i+1
            f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1;  
            // 中心拓展
            while (t[i + f[i]] == t[i - f[i]]) ++f[i];
            // 动态维护 iMax 和 rMax
            if (f[i] > rMax - iMax + 1)  //更新最大回文子串及其右边界
            {
                iMax = i;
                rMax = i + f[i] - 1;
            }
//          if (i + f[i] - 1 > rMax)  //更新最右回文子串及其右边界,但它不一定是最长回文子串,求回文串数可用这个条件
//         {
//                iMax = i;
//                rMax = i + f[i] - 1;
//          }
//            ans += (f[i] / 2);
        }

        cout << f[iMax] - 1 << endl;  //这是最大回文串长度

//      for (int i = iMax - f[iMax] + 1; i <= rMax; ++i)  //这里输出最大回文串
//        {
//            if (t[i] != '#')
//            {
//                cout << t[i];
//            }
//        }
    }

例题:

/*
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:"abc"
输出:3
解释:三个回文子串: "a", "b", "c"
示例 2:
输入:"aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
*/  
class Solution {
public:
    int countSubstrings(string s) {
        int n = s.size();
        string t = "$#";
        for (const char &c: s) {
            t += c;
            t += '#';
        }
        n = t.size();
        t += '!';

        auto f = vector <int> (n);
        int iMax = 0, rMax = 0, ans = 0;
        for (int i = 1; i < n; ++i) {
            // 初始化 f[i]
            f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1;
            // 中心拓展
            while (t[i + f[i]] == t[i - f[i]]) ++f[i];
            // 动态维护 iMax 和 rMax
            if (i + f[i] - 1 > rMax) {
                iMax = i;
                rMax = i + f[i] - 1;
            }
            // 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
            ans += (f[i] / 2);
        }

        return ans;
    }
};
全部评论

相关推荐

冲芭芭拉鸭:你这图还挺新,偷了。
投递美团等公司10个岗位
点赞 评论 收藏
分享
牛客737698141号:他们可以看到在线简历的。。。估计不合适直接就拒了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务