Java 算法-最大回文子串(Manacher算法)

??今天在lintCode做了一道面試題当悔,非常的簡單傅瞻,利用常規(guī)的方法計算起來非常的簡答踢代,但是有意思的就是挑戰(zhàn)項(xiàng)。我們先來看看題:

題意:

給出一個字符串(假設(shè)長度最長為1000)嗅骄,求出它的最長回文子串胳挎,你可以假
定只有一個滿足條件的最長回文串。

樣例:

給出字符串 "abcdzdcab"溺森,它的最長回文子串為 "cdzdc"慕爬。

挑戰(zhàn):

O(n2) 時間復(fù)雜度的算法是可以接受的,如果你能用 O(n) 的算法那自然更好

??常規(guī)的方法在這里就不展示屏积,這里最主要的是展示Manacher算法医窿。

1.Manacher算法

??首先說明一下,Manacher算法能夠使得在O(n)的時間復(fù)雜度下找到最長的回文子串炊林。

(1).Manacher算法的概述

??Manacher算法只能解決長度為奇數(shù)的字符串姥卢,所以Manacher算法利用了一個比較巧妙的方法來同時解決長度為奇數(shù)或者偶數(shù)的字符串。Manacher算法通過轉(zhuǎn)換字符串來實(shí)現(xiàn)的渣聚,例如:原來的字符串:abc独榴,經(jīng)過轉(zhuǎn)換得到:#a#b#c#,這樣原來的字符串長度不管是奇數(shù)還是偶數(shù)奕枝,最終轉(zhuǎn)換都能夠得到一個長度為奇數(shù)的字符串棺榔。
??其次,Manacher算法通常還需要一個數(shù)組(我們假設(shè)是倍权,len數(shù)組)來記錄每一個字符在原字符串中的回文字符串的最大長度掷豺,其實(shí)實(shí)際上是,該字符在原來的字符串中得到的最長回文字符串的一半長度薄声。
??例如:aba当船,經(jīng)過轉(zhuǎn)換得到:#a#b#a#,b能得到的最長回文字符串是:#a#b#a#默辨,我們假設(shè)b的下標(biāo)是i德频,得到的最長字符串的第一個字符下標(biāo)是left,最后一個字符的下標(biāo)是right那么b對應(yīng)的值是:right - i + 1缩幸;
??同時壹置,我們還能知道的是,i對應(yīng)的字符得到的最大回文子串長度是:len[i] - 1,例如:上面的例子表谊,b的下標(biāo)是3钞护,所以len[3] = 4,那么b對應(yīng)的回文字符串a(chǎn)ba,長度恰好是len[3] - 1 = 3爆办。這個是為什么呢难咕?我們假設(shè)原來的字符串為oldString(沒有經(jīng)過轉(zhuǎn)換的),轉(zhuǎn)換過后的字符串為newString,假設(shè)oldString長度為length余佃,那么newString的長度就為2 * length + 1,所以得到的字符串長度肯定為奇數(shù)暮刃。對于newString中的第i個字符對應(yīng)的回文字符串,長度肯定為2 * len[i] - 1(這個你們可以簡單的去舉例子測試一下)爆土,同時椭懊,經(jīng)過觀察得知,2 * len[i] - 1個字符中步势,肯定有l(wèi)en[i]個是#,其余的才是正常的符號氧猬,因?yàn)樵谒械幕匚淖址?的個數(shù)總是與其他符號的個數(shù)相差為1。

(2).len數(shù)組的計算

??首先立润,我們從左往右計算len[i]狂窑,當(dāng)我們計算len[i]時,len[j]已經(jīng)計算完畢(0 < j < i)桑腮。
??我們假設(shè),在已經(jīng)計算了的字符當(dāng)中取得最長回文子串的右端點(diǎn)的最大值(該回文字符串不一定是最長的回文字符串蛉幸,只是要求該回文字符串右端下標(biāo)最大)破讨,假設(shè)最大值為rightIndex,并且設(shè)置該回文子串中心的位置是centerIndex奕纫,那么分為兩種情況:

??A.i < rightIndex

??我們假設(shè)以centerIndex為中心提陶,與i對應(yīng)的是j。如圖:



??我們知道的是匹层,以centerIndex為中心隙笆,回文字符串能達(dá)到rightIndex,那么此時有分為兩種情況:
??如果i + len[j] < P,也就是說升筏,以j為中心的回文字符串在以centerInde為中心的回文字符串內(nèi)部撑柔,此時可以得到以j為中心的回文字符串與以i為中心的回文字符串是相同的,為什么呢您访?因?yàn)樗麄冊谝詂enterIndex為中心的回文字符串的內(nèi)部铅忿。所以可以得到的是,len[i] = len[j]灵汪。
??如果i + len[j] >= P的話檀训,也就是說,以i為中心的回文字符串有一部分在以centerIndex為中心的回文字符串的外部享言,此時外部這一部分需要我們一個一個的計算峻凫。

??B.i > rightIndex

??如果i > rightIndex的話,那就說明览露,以i為中心的回文字符串一點(diǎn)都沒有匹配荧琼。所以需要我們一個一個的匹配了。

2.代碼

public static String longestPalindrome(String string) {

        //-----------------------------------
        //轉(zhuǎn)換字符串
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("#");
        for (int i = 0; i < string.length(); i++) {
            stringBuilder.append(string.charAt(i));
            stringBuilder.append("#");
        }
        //-----------------------------------
        int rightIndex = 0;
        int centerIndex = 0;
        //求len中的最大
        int answer = 0;
        //answer最大時的中心
        int index = 0;
        int len[] = new int[stringBuilder.length() ];
        for (int i = 1; i < stringBuilder.length(); i++) {
            //當(dāng)rightIndex > i,那么我們就在rightIndex - i 與len[2 * centerIndex - i](len[j])铭腕,取得最小值
            //因?yàn)楫?dāng)i + len[j] < rightIndex時银择,我們就把len[i]更新為len[j]
            //但是如果i + len[j] >= rightIndex時,我們暫且將len[i]定更新為rightIndex - i,超出的部分需要我們一個一個的匹配
            if (rightIndex > i) {
                len[i] = Math.min(rightIndex - i, len[2 * centerIndex - i]);
            } else {
                len[i] = 1;
            }
            //一個一個匹配
            //要么是超出的部分累舷,要么是i > rightIndex
            while(i - len[i] >= 0 && i + len[i] < stringBuilder.length() && stringBuilder.charAt(i - len[i]) == stringBuilder.charAt(i + len[i])) {
                len[i]++;
            }
            //當(dāng) len[i] + i > rightIndex,我們需要更新centerIndex和rightIndex
            //至于為什么會這樣做浩考,理解一下rightIndex和centerIndex的含義
            if(len[i] + i > rightIndex) {
                rightIndex = len[i] + i;
                centerIndex = i;
            }
            if(len[i] > answer) {
                answer = len[i];
                index = i;
            }
        }
        //截取字符串
        //為什么index - answer + 1,因?yàn)閘en[i] - 1才是原來的回文字符串長度,而answer記錄的是len中最大值
        return stringBuilder.substring(index - answer + 1, index + answer).replace("#", "");
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末被盈,一起剝皮案震驚了整個濱河市析孽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌袜瞬,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件身堡,死亡現(xiàn)場離奇詭異邓尤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門溯香,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禀梳,“玉大人,你說我怎么就攤上這事嘴瓤∩秆瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵纸肉,是天一觀的道長胳泉。 經(jīng)常有香客問我扇商,道長,這世上最難降的妖魔是什么返吻? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任沐旨,我火速辦了婚禮,結(jié)果婚禮上这吻,老公的妹妹穿的比我還像新娘移怯。我一直安慰自己,他們只是感情好这难,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布舟误。 她就那樣靜靜地躺著,像睡著了一般姻乓。 火紅的嫁衣襯著肌膚如雪嵌溢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天蹋岩,我揣著相機(jī)與錄音赖草,去河邊找鬼。 笑死剪个,一個胖子當(dāng)著我的面吹牛秧骑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扣囊,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼乎折,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了如暖?” 一聲冷哼從身側(cè)響起笆檀,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盒至,沒想到半個月后酗洒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體士修,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年樱衷,在試婚紗的時候發(fā)現(xiàn)自己被綠了棋嘲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡矩桂,死狀恐怖沸移,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侄榴,我是刑警寧澤雹锣,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站癞蚕,受9級特大地震影響蕊爵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜桦山,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一攒射、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恒水,春花似錦会放、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至御雕,卻和暖如春窗市,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饮笛。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留论熙,地道東北人福青。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像脓诡,于是被迫代替她去往敵國和親无午。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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

  • 最長回文子串——Manacher 算法 1. 問題定義 最長回文字符串問題:給定一個字符串祝谚,求它的最長回文子串長度...
    林大鵬閱讀 2,739評論 0 6
  • 基礎(chǔ)了解 回文串:是一個正讀和反讀都一樣的字符串宪迟。例如:level ,asdffdsa 回文子串:字符串中交惯,滿足回...
    來自火星的程序猿閱讀 672評論 0 0
  • 上一篇KMP算法之后好幾天都沒有更新次泽,今天介紹最長回文子串穿仪。 首先介紹一下什么叫回文串,就是正著讀和倒著讀的字符順...
    zero_sr閱讀 2,263評論 2 8
  • 這次要記錄的是一個經(jīng)典的字符串的題目意荤,也是一個經(jīng)典的馬拉車算法的實(shí)踐啊片。相信在很多地方都會考到或者問到這道題目,這道...
    檸檬烏冬面閱讀 2,900評論 0 9
  • 問題定義 最長回文子串問題:給定一個字符串玖像,求它的最長回文子串長度紫谷。 解法1:暴力解法 找到字符串的所有子串,判斷...
    HITMiner閱讀 661評論 0 2