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爲中心的迴文串半徑
參考下圖:
image

  • 關鍵點(動態規劃思想)
    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);
    }
發佈了28 篇原創文章 · 獲贊 2 · 訪問量 5158
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章