leetcode5 最长回文子串

leetcode5 最长回文子串(Manacher算法)

1.题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

示例:

输入: “babad”
输出: “bab”

注意: “aba”也是一个有效答案。

2.manacher算法

奇回文(如 aba)和偶回文(如abba)归一化处理

  • 在字符串s的前端添加 $** 字符防止越界(代码中有说明越界点),字符串s尾端已有 ‘\0’**
  • 添加#字符于字符串s各字符之间
    如abacddc
i 0 1 2 3 4 5 6 7
s[i] a b a c d d c \0
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
s_new[i] $ # a # b # a # c # d # d # c #

* 参数设定
id 为当前最长回文串的中心
mx 为当前最长回文串的右边界
p[i] 为以i为中心的回文串半径
参考下图:
leetcode5 最长回文子串_第1张图片

  • 关键点(动态规划思想)
    i 在当前最长回文子串内时( mx>i ),以 i 为中心的回文子串长度:

    p[i] = max > i ? min(p[2*id - i], mx-i) : 1;
    
    1. 要么等于其 关于id对称点j为中心的回文子串长度(前提:以j为中心的回文子串包含在当前最长回文子串内)
    2. 要么以其为中心的回文子串右端 超出mx ( 此时p[i]设为mx-i,且继续寻找边界 )

3.代码

string longestPalindrome(string s) {
        int max_str = 0; // 最长回文子串的长度
        int front_index; // 最长回文子串的起始位
        if(s.empty())
            return 0;

        // 初始化s
        string new_s;
        new_s.push_back('$');
        new_s.push_back('#');
        for(int i = 0; i < s.length(); i++)
        {
            new_s.push_back(s[i]);
            new_s.push_back('#');
        }

        vector<int> p(new_s.length());

        int id = 0;
        int mx = 0;
        for(int i = 1; i < new_s.length(); i++)
        {
            // p[i]为当前i位置回文子串的半径,回文子串长度为p[i] - 1
            // 加速方式(动态规划):p[i] = max > i ? min(p[2*id - i], mx-i) : 1;
            if(mx > i)
                p[i] = min(p[2*id - i], mx-i);
            else
                p[i] = 1;

            // 前后搜索,越界点
            while(new_s[i + p[i]] == new_s[i - p[i]])
                p[i]++;

            if(p[i] - 1 > max_str){
                front_index = (i - p[i] + 2)/2 - 1; // 一定是 #......# 的形式
                max_str = p[i] - 1;
            }
            if(p[i] + i > mx){
                mx = p[i] + i;
                id = i;
            }
        }

        return s.substr(front_index, max_str);
    }

你可能感兴趣的:(C++,算法,Leetcode)