[DP/Manacher]最長(zhǎng)回文子串(經(jīng)典DP)_Short

------------6.11更新-----------
明天(tuo yan)繼續(xù)把 Basic & Tall刷了,改日再戰(zhàn)

------------Original------------
為什么說這個(gè)是個(gè)經(jīng)典DP呢,它經(jīng)典到與最長(zhǎng)公共子序列一樣經(jīng)典.
幾萬(wàn)種變體:
這里我要來歸納一下,免得有人像我一樣被虐成狗.

Short - 求給定串的最長(zhǎng)回文子串
Basic - 給定一個(gè)字符串s,你可以從中刪除一些字符,使得剩下的串是一個(gè)回文串。如何刪除才能使得回文串最長(zhǎng)呢?輸出需要?jiǎng)h除的字符個(gè)數(shù). ---->這是個(gè)回文子序列,不是回文子串,別尼瑪搞混了
Tall.. - 給定一個(gè)數(shù)字串digit_str,每次操作可以把相鄰2個(gè)數(shù)字相加并替換掉這2個(gè)數(shù)字,問至少操作幾次可以得到一個(gè)回文數(shù)字串?輸出最少操作次數(shù).
(to be added)

Short(超小杯)

基本的最長(zhǎng)回文子串.
有暴力/DP/Manacher三種算法.

其中Manacher馬拉車算法是利用了回文串的特性,做到了盡可能利用已知信息,達(dá)到了O(N)時(shí)間復(fù)雜度.

基本上搜索一下都可以找到很多信息.

暴力

不多說,如果筆試肯定超時(shí).
枚舉子串時(shí)可以按照子串的長(zhǎng)度從1 .. str.size()來枚舉.
時(shí)間復(fù)雜度 - O(N3),網(wǎng)上大多數(shù)都說O(N3),但我覺得應(yīng)該是在O(N2)和O(N3)之間.------------->好好地估算過了確實(shí)是個(gè)O(N3)級(jí)數(shù).(只不過這個(gè)乘了一個(gè)`x/1`的系數(shù),無(wú)關(guān)緊要了反正還是O(N3))

DP法

第一時(shí)間想到用F[i,j]表示i..j的最長(zhǎng)回文子串長(zhǎng)度.馬上就有F[0,l-1]就是這里需要求的整個(gè)串的最長(zhǎng)回文子串長(zhǎng)度.

  • 錯(cuò)誤的DP狀態(tài)轉(zhuǎn)移方程
    我第一時(shí)間寫下了這樣的轉(zhuǎn)移方程:
      F[i,j] = max { F[i+1, j-1] + 2 ----- if str[i] == str[j] ///fatal error here:如果i+1..j-1非回文但又有str[i] == str[j]怎么辦?
                     F[i+1,j]        ----- otherwise1
                     F[i,j-1]        ----- otherwise2
                    }
    

錯(cuò)誤的點(diǎn)正是這里,F[i,j] = F[i+1,j-1]+2的條件是比較嚴(yán)格的.

  • 正確的DP狀態(tài)轉(zhuǎn)移方程 0x1
      F[i,j] = max { F[i+1, j-1] + 2 ----- if str[i] == str[j] && F[i+1, j-1] == j-1-(i+1)+1 ////如果i+1..j-1非回文但又有str[i] == str[j]怎么辦?
                     F[i+1,j]        ----- otherwise1
                     F[i,j-1]        ----- otherwise2
                    }
    

或者是網(wǎng)上其他人給的true/false矩陣,然后需要2個(gè)變量每次更新一下最長(zhǎng)子串的長(zhǎng)度和起始點(diǎn).

  • 正確的DP狀態(tài)轉(zhuǎn)移方程 0x2
      isP[i,j] = {
                    isP[i+1,j-1] ----- if str[i] == str[j]
                    false        ----- otherwise
                 }
    
  • DP的填表方向/初始狀態(tài) ---- 不多說
Manacher法

也不多說,這個(gè)網(wǎng)上有很多詳解的.

實(shí)現(xiàn)
  • 代碼()
    有興趣的同學(xué)一起來搞:<a href = https://github.com/exctPuzzles/exctpuzzs/blob/master/solutions/algs/max_plalindrome_substr.cc>github_page</a>

include <cstdio>

#include <string>
using namespace std;
#define Max(a,b) ((a) > (b) ? (a):(b))
#define Min(a,b) ((a) < (b) ? (a):(b))
#define SIZE 1005
//#define DBG_1
#define DBG_2
string::size_type F[SIZE][SIZE];//the length array
//auto init to zero
string::size_type ST[SIZE][SIZE];//the start_ofs array
class Solution {
public:
    bool isP(string &x, string::size_type st, string::size_type len){
        string::size_type ed = st + len - 1;
        while(st < ed){
            if(x[st] != x[ed]){
                return false;
            }
            st++;ed--;
        }
        return true;
    }
    string max_plalindrome_substr_bf(string x){
    //just simply find all substring & see if plalindrome.
    //time complexity - O(N^3)
    //a little bit optimize
        string::size_type l = x.size(), i, st, max_l = 1, st_l;
        for(i = 2; i <= l;i++){
            for(st = 0; st + i - 1 < l ; st++){
                if(max_l >= i){
                    break;
                }
                if(isP(x, st, i)){
                    max_l = i;
                    st_l = st;
                }
            }
        }
#ifdef DBG_2
        for(i = 0; i < st_l; i++){
            printf(" ");
        }
        printf("%s\n", x.substr(st_l, max_l).c_str());
#endif      
        return x.substr(st_l, max_l);
    }
    
    string max_plalindrome_substr_dp(string x){
    //
    //time complexity - O(N^2) , space complexity - O(N^2)
    //
        string::size_type st_l, max_l, l = x.size(), i, st, ed;
        string::size_type a,b,c;
        for(i = 0; i < l; i++){
            F[i][i] = 1;
            ST[i][i] = i;
        }
        for(i = 2; i <= l; i++){//for every substring's length,direction to fill the DP array
            for(st = 0; (ed = st + i - 1) < l; st++){
                //a = x[st] == x[ed] ? F[st + 1][ed - 1] + 2 : 0;/////a fatal bug here
                a = x[st] == x[ed] && F[st + 1][ed - 1] == ed - 1 - st? F[st + 1][ed - 1] + 2 : 0;//the situation left for b&c
                b = F[st + 1][ed];
                c = F[st][ed - 1];
                if(a > b){
                    if(a > c){
                        F[st][ed] = a;
                        ST[st][ed] = st;
                    }else{
                        F[st][ed] = c;
                        ST[st][ed] = ST[st][ed - 1];
                    }    
                }else{
                    if(b > c){
                        F[st][ed] = b;
                        ST[st][ed] = ST[st + 1][ed];
                    }else{
                        F[st][ed] = c;
                        ST[st][ed] = ST[st][ed - 1];//bug fix
                    }
                }
            }
        }
#ifdef DBG_1
        for(i = 0; i < l; i++){
            for(string::value_type j = 0; j < l; j++){
                printf("%ld ", F[i][j]);
            }
            printf("\n");
        }
#endif      
#ifdef DBG_2
        for(i = 0; i < ST[0][l-1]; i++){
            printf(" ");
        }
        printf("%s\n", x.substr(ST[0][l-1], F[0][l-1]).c_str());
#endif
        return x.substr(ST[0][l-1], F[0][l-1]);

    }
    
    bool isP_arr[SIZE][SIZE];
    
    string max_plalindrome_substr_dp2(string s){
        string::size_type i, l = s.size(), st, ed, max_l = 1, max_st;
        for(i = 0; i < l; i++){//len = 1
            isP_arr[i][i] = true;
            isP_arr[i+1][i] = true;
        }
        for(i = 2; i <= l; i++){
            for(st = 0; (ed = st + i - 1) < l; st++){
                isP_arr[st][ed] = s[st] == s[ed] ? isP_arr[st+1][ed-1] : false;
                if(isP_arr[st][ed] && i > max_l){
                    max_l = i;
                    max_st = st;
                }
            }
        }
#ifdef DBG_2
        for(i = 0; i < max_st; i++){
            printf(" ");
        }
        printf("%s\n", s.substr(max_st, max_l).c_str());
#endif      
        return s.substr(max_st, max_l);
    }
#define dou_SIZE 2010
    string max_plalindrome_substr_mnc(string s){
        string tmp(s);
        string::size_type po, r_mx, Len[dou_SIZE], i, j, mx_iter, l, rt, lt;
        for(i = 0; i <= s.size(); i++){
            tmp.insert( 2 * i, "#");
        }//convert the string to #s#t#r#i#n#g#
        
//      printf("%s\n", tmp.c_str());
        l = tmp.size();
        po = 0;
        r_mx = 0;
        string::size_type start_point, mirr, length;
        for(i = 0; i < l; i++){//calc Len[i]
            if(i < r_mx){
                mirr = 2 * po - i;
                if(Len[mirr] >= r_mx - i + 1){
                    Len[i] = r_mx - i + 1;
                    start_point = r_mx - i + 1;
                }else{
                    Len[i] = Len[mirr];
                    continue;
                }
            }else{
                Len[i] = 1;////
                start_point = 1;
            }
            
            mx_iter = Min(i - 0 + 1, l - 1 - i + 1 ) - 1;
            for(j = start_point/**/; j <= mx_iter; j++){
                lt = i - j;
                rt = i + j;
                if(tmp[lt] == tmp[rt]){
                    Len[i]++;
                    if(Len[i] > r_mx - po + 1){
                        po = i;
                        r_mx = po + Len[i] - 1;
                    }
                }else{
                    break;
                }
            }
        }
        if(tmp[po] == '#'){
            start_point = po/2 - (Len[po] - 1)/2;
            length = (Len[po] - 1);
        }else{
            length = (Len[po] - 1);
            start_point = (po-1)/2 - (length - 1)/2;            
        }
#ifdef DBG_2
        for(i = 0; i < start_point; i++){
            printf(" ");
        }
        printf("%s\n", s.substr(start_point, length).c_str());
#endif
        return s.substr(start_point, length);
    }
    
    string longestPalindrome(string s) {
        string ret;
#ifdef DBG_2
        printf("%s\n", s.c_str());
        ret = max_plalindrome_substr_bf(s);
        printf("==============================================\n");
        printf("%s\n", s.c_str());
        max_plalindrome_substr_dp(s);
        printf("==============================================\n");
        printf("%s\n", s.c_str());
        max_plalindrome_substr_dp2(s);
        
        printf("==============================================\n");
        printf("%s\n", s.c_str());
        max_plalindrome_substr_mnc(s);
#endif  
        return ret;
    }
};
  
#include <iostream>
int main()
{
    Solution s;
    string str;
    while(getline(cin, str)){
        s.longestPalindrome(str);
        //printf("longest palindromic substr - %s\n", s.longestPalindrome(str2).c_str());
    }
    return 0;
}
```
  • 測(cè)試 - leetcode/5.longest palindromic substring 通過.
echo "zgtklhfzomzjckwmluvivvcmhjrwkuvcjrxojobpdedpamdshcwwsetfbacvonecrdvugeibglvhxuymjvoryqjwullvzglqazxrdmczyvbgakjagttrezmvrlptiwoqkrtxuroeqmryzsgokopxxdpbejmtwvpnaqrgqladdszhdwxfckmewhdvihgvacueqhvwvjxoitlpfrckxkuksaqzjpwgoldyhugsacflcdqhifldoaphgdbhaciixouavqxwlghadmfortqacbffqzocinvuqpjthgekunjsstukeiffjipzzabkuiueqnjgkuiojwbjzfynafnlcaryygqjfixaoeowhkxkbsnpsvnbxuywfxbnuoemxynbtgkqtjvzqikbafjnpbeirxxrohhnjqrbqqzercqcrcswojyylunuevtdhamlkzqnjrzibwckbkiygysuaxpjrgjmurrohkhvjpmwmmtpcszpihcntyivrjplhyrqftghglkvqeidyhtmrlcljngeyaefxnywpfsualufjwnffyqnpitgkkyrbwccqggycrvoocbwsdbftkigrkcbojuwwctknzzmvhbhbfzrqwzllulbabztqnznkqdyoqnrxhwavqhzyzvmmmphzxbikpharseywpfsqyybkynwbdrgfsaxduxojcdqcjuaywzbvdjgjqtoffasiuhvxcaockebkuxpiomqmtvsqhnyxfjceqevqvnapbk " | ./test > 1.txt
zgtklhfzomzjckwmluvivvcmhjrwkuvcjrxojobpdedpamdshcwwsetfbacvonecrdvugeibglvhxuymjvoryqjwullvzglqazxrdmczyvbgakjagttrezmvrlptiwoqkrtxuroeqmryzsgokopxxdpbejmtwvpnaqrgqladdszhdwxfckmewhdvihgvacueqhvwvjxoitlpfrckxkuksaqzjpwgoldyhugsacflcdqhifldoaphgdbhaciixouavqxwlghadmfortqacbffqzocinvuqpjthgekunjsstukeiffjipzzabkuiueqnjgkuiojwbjzfynafnlcaryygqjfixaoeowhkxkbsnpsvnbxuywfxbnuoemxynbtgkqtjvzqikbafjnpbeirxxrohhnjqrbqqzercqcrcswojyylunuevtdhamlkzqnjrzibwckbkiygysuaxpjrgjmurrohkhvjpmwmmtpcszpihcntyivrjplhyrqftghglkvqeidyhtmrlcljngeyaefxnywpfsualufjwnffyqnpitgkkyrbwccqggycrvoocbwsdbftkigrkcbojuwwctknzzmvhbhbfzrqwzllulbabztqnznkqdyoqnrxhwavqhzyzvmmmphzxbikpharseywpfsqyybkynwbdrgfsaxduxojcdqcjuaywzbvdjgjqtoffasiuhvxcaockebkuxpiomqmtvsqhnyxfjceqevqvnapbk
                                       pdedp
==============================================
zgtklhfzomzjckwmluvivvcmhjrwkuvcjrxojobpdedpamdshcwwsetfbacvonecrdvugeibglvhxuymjvoryqjwullvzglqazxrdmczyvbgakjagttrezmvrlptiwoqkrtxuroeqmryzsgokopxxdpbejmtwvpnaqrgqladdszhdwxfckmewhdvihgvacueqhvwvjxoitlpfrckxkuksaqzjpwgoldyhugsacflcdqhifldoaphgdbhaciixouavqxwlghadmfortqacbffqzocinvuqpjthgekunjsstukeiffjipzzabkuiueqnjgkuiojwbjzfynafnlcaryygqjfixaoeowhkxkbsnpsvnbxuywfxbnuoemxynbtgkqtjvzqikbafjnpbeirxxrohhnjqrbqqzercqcrcswojyylunuevtdhamlkzqnjrzibwckbkiygysuaxpjrgjmurrohkhvjpmwmmtpcszpihcntyivrjplhyrqftghglkvqeidyhtmrlcljngeyaefxnywpfsualufjwnffyqnpitgkkyrbwccqggycrvoocbwsdbftkigrkcbojuwwctknzzmvhbhbfzrqwzllulbabztqnznkqdyoqnrxhwavqhzyzvmmmphzxbikpharseywpfsqyybkynwbdrgfsaxduxojcdqcjuaywzbvdjgjqtoffasiuhvxcaockebkuxpiomqmtvsqhnyxfjceqevqvnapbk
                                       pdedp
==============================================
zgtklhfzomzjckwmluvivvcmhjrwkuvcjrxojobpdedpamdshcwwsetfbacvonecrdvugeibglvhxuymjvoryqjwullvzglqazxrdmczyvbgakjagttrezmvrlptiwoqkrtxuroeqmryzsgokopxxdpbejmtwvpnaqrgqladdszhdwxfckmewhdvihgvacueqhvwvjxoitlpfrckxkuksaqzjpwgoldyhugsacflcdqhifldoaphgdbhaciixouavqxwlghadmfortqacbffqzocinvuqpjthgekunjsstukeiffjipzzabkuiueqnjgkuiojwbjzfynafnlcaryygqjfixaoeowhkxkbsnpsvnbxuywfxbnuoemxynbtgkqtjvzqikbafjnpbeirxxrohhnjqrbqqzercqcrcswojyylunuevtdhamlkzqnjrzibwckbkiygysuaxpjrgjmurrohkhvjpmwmmtpcszpihcntyivrjplhyrqftghglkvqeidyhtmrlcljngeyaefxnywpfsualufjwnffyqnpitgkkyrbwccqggycrvoocbwsdbftkigrkcbojuwwctknzzmvhbhbfzrqwzllulbabztqnznkqdyoqnrxhwavqhzyzvmmmphzxbikpharseywpfsqyybkynwbdrgfsaxduxojcdqcjuaywzbvdjgjqtoffasiuhvxcaockebkuxpiomqmtvsqhnyxfjceqevqvnapbk
                                       pdedp
==============================================
zgtklhfzomzjckwmluvivvcmhjrwkuvcjrxojobpdedpamdshcwwsetfbacvonecrdvugeibglvhxuymjvoryqjwullvzglqazxrdmczyvbgakjagttrezmvrlptiwoqkrtxuroeqmryzsgokopxxdpbejmtwvpnaqrgqladdszhdwxfckmewhdvihgvacueqhvwvjxoitlpfrckxkuksaqzjpwgoldyhugsacflcdqhifldoaphgdbhaciixouavqxwlghadmfortqacbffqzocinvuqpjthgekunjsstukeiffjipzzabkuiueqnjgkuiojwbjzfynafnlcaryygqjfixaoeowhkxkbsnpsvnbxuywfxbnuoemxynbtgkqtjvzqikbafjnpbeirxxrohhnjqrbqqzercqcrcswojyylunuevtdhamlkzqnjrzibwckbkiygysuaxpjrgjmurrohkhvjpmwmmtpcszpihcntyivrjplhyrqftghglkvqeidyhtmrlcljngeyaefxnywpfsualufjwnffyqnpitgkkyrbwccqggycrvoocbwsdbftkigrkcbojuwwctknzzmvhbhbfzrqwzllulbabztqnznkqdyoqnrxhwavqhzyzvmmmphzxbikpharseywpfsqyybkynwbdrgfsaxduxojcdqcjuaywzbvdjgjqtoffasiuhvxcaockebkuxpiomqmtvsqhnyxfjceqevqvnapbk
                                       pdedp
想做成一件事最好的辦法就是——做他
Just father Fucking Do it.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,414評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,465評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,823評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,000評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,554評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,513評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,722評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,237評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,482評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容