【leetcode 5. 最长回文子串】解题报告

方法一:中心扩展算法

解题思路:

算法时间复杂度:$O(n^{3})$

    string longestPalindrome(string s) {        
        int idx = 0, maxL = 0;
        for (int i = 0; i < s.size(); ++i)
        {
            for (int j = 0; i - j >= 0 && i + j < s.size(); ++j)    // 奇数
            {
                if (s[i - j] != s[i + j])
                    break;
                if (2 * j + 1 > maxL)
                {
                    maxL = 2 * j + 1;
                    idx = i - j;
                }
            }
            for (int j = 0; i - j >= 0 && i + j + 1 < s.size(); ++j)    // 偶数
            {
                if (s[i-j]!=s[i+j+1])
                    break;
                if (2 * j + 2 > maxL)
                {
                    maxL = 2 * j + 2;
                    idx = i - j;
                }
            }
        }
        return s.substr(idx, maxL);
    }

方法二:manacher(马拉车法)

解题思路:详见P3805 【模板】manacher算法

算法时间复杂度为:$O(n)$

    int pos[2005],p[2005];
    string longestPalindrome(string s) {        
        /* 填充字符,统一为奇数串 */
        string s_new="~";
        for (int i=0,k=1;i<s.size();++i)
        {
            s_new+="#";
            s_new+=s[i];
            pos[k++]=i; // 记录新字串与原始字串的位置关系
            pos[k++]=i;
        }
        s_new+="#";
        
        /* manacher */
        int m=0,r=0,maxL=0,idx=0;
        for (int i=1;i<s_new.size();++i)
        {
            // 获取已知的最小回文半径
            if (i<r)
                p[i]=min(p[2*m-i],r-i);
            else
                p[i]=1;
            // 暴力拓展左右两侧
            while (s_new[i-p[i]]==s_new[i+p[i]])
                p[i]++;
            // 新的回文半径比较大,则更新
            if (r-i<p[i])
            {
                m=i;
                r=i+p[i];
            }
            // 更新回文长度(原始字串的回文长度为新字串回文半径-1)
            if (p[i]-1>maxL)
            {
                maxL=p[i]-1;
                idx=pos[i]-maxL/2;  // 更新原始回文字串的起始位置
            }
        }
        return s.substr(idx,maxL);
    }

猜你喜欢

转载自www.cnblogs.com/brianyi/p/10812527.html