1. 程式人生 > >java manacher演算法計算最長迴文字串

java manacher演算法計算最長迴文字串

求解最長迴文字串樸素演算法

最樸素的演算法是暴力解法就不談了,時間複雜度是O(n3)。

比最樸素解法稍微好一些的解法是O(n2)的一種解法,思路是從對稱軸開始考慮,根據迴文字串長度的奇偶分為兩種情況,如果最長的迴文字串為偶數位,那麼他的對稱軸是中間部分,如果是奇數位則為中間的一個字元。那麼從該字串的第一個字元開始一共有n+(n-1)個對稱軸,每個對稱軸都需要便利一遍n來找最長的迴文字串,所以演算法複雜度是O(n2)。

普通的情況下,在沒有聽說過其他解法的時候我們最好的處理就是這種方法了,下面介紹一種演算法複雜度為O(n)的演算法,manacher演算法。

manacher演算法解決最長迴文字串問題

剛才的第二種解法中我們不斷的更改對稱軸並進行匹配。在這個過程中我們貌似進行了很多重複的工作,比如相鄰的兩個對稱軸我們檢測的迴文字串會重複的不斷檢測這兩個字元旁邊的字元。演算法之所以能夠優化的根本原因就是把重複計算去掉了,那麼我們怎麼樣才能減少相近字元的重複計算呢?

str1 : abacbcac

str2 : #a#b#a#c#b#c#a#c#

我們要計算的就是str1的最長迴文字串,manacher演算法的思路是把字串包括前後的所有空隙都插入一個相同的其他字元,就像例子中我們構造出了str2字串。無論原字串是奇還是偶構造出來的結果都是一個奇數位的字串。

迴文半徑

為了方便說明演算法,我們引入迴文半徑的概念,迴文半徑是指在str2中每個字元(每個字元不包括空隙,但是包括#號)的迴文序列從對稱軸到最遠端的長度(包含自身)。那麼對於str2中的每個字元我們都可以計算他的最長迴文半徑。

s t r 2:#a#b#a#c#b#c#a#c#

半徑 :12131212161212121

我們通過肉眼計算得到了迴文半徑,那麼接下來有個很重要的定理:

str1中最長的迴文字串長度是str2中最大回文半徑-1.

我們觀察str1中的最大回文字串為acbca為5,str2中的最大回文半徑是6,剛好符合上面的定理。說實話,這個其中的具體原因是什麼,這裡不解釋,因為這個演算法被創造出來是一個數學的過程,但是我們主要要去使用這個演算法,如果你在面試的時候只有一支筆一張紙,沒聽說過這個演算法你是不可能在短時間自己證明出它的,我們要做的就是熟練運用。

如何求解迴文半徑?

問題簡單了,我們開始要求迴文字串,現在只需要計算迴文半徑就可以了,那麼如何用最低的複雜度計算迴文半徑呢?

首先我們看最簡單的方法,我們只需要求所有的迴文半徑,每個字元進行便利即可,最多需要O(n2)的複雜度,這聽起來和最開始的方法的複雜度很像,那麼現在的計算和剛開始的計算有什麼區別呢?開始的計算方法要計算空隙和字元所有的迴文情況,現在只需要計算每個字元的迴文半徑即可,不需要計算空隙,那麼相比較之前的方法計算迴文半徑會出現很多重複次的計算。

只要我們能夠避免重複計算,那麼我們就可以獲得更小的複雜度計算方法。

如何避免重複計算呢?我們從str2字串首部開始,將第一個點標記為pos,將該點右側最長半徑處的邊緣點記作MaxR,表示右側最大值點,因為我們知道字串具有對稱性,所以所有在pos和MaxR之間的字元i都有兩種情況,第一種是該字元i的半徑和pos左側相應位置的j點的半徑長相同;第二種情況是i半徑長度比j還大,i的半徑可以擴充套件到MaxR的右側,那麼這個時候我們進行手動遍歷以i為對稱軸的對稱的兩點來計算i的最大半徑,並在這之後更新i為新的pos,i的右側為新的MaxR。除此之外還有一種情況就是i的點在MaxR右側,此時我們正常以i為對稱軸進行左右對稱判斷更新i的半徑,但是無論結果如何都更新i變為pos,i的右側為MaxR。

演算法如上,我簡單的總結就是,如果i在pos和MaxR中間我們有可能通過pos的對稱點快速計算出i的半徑,否則進行樸素的對稱計算,但是因為我們採用的這種標記最右側MaxR的方法,所以我們會避免很多重複計算,時間複雜度為O(n+m)考慮到m是常數,複雜度為O(n)。

相關推薦

java manacher演算法計算字串

求解最長迴文字串樸素演算法 最樸素的演算法是暴力解法就不談了,時間複雜度是O(n3)。 比最樸素解法稍微好一些的解法是O(n2)的一種解法,思路是從對稱軸開始考慮,根據迴文字串長度的奇偶分為兩種情況,如果最長的迴文字串為偶數位,那麼他的對稱軸是中間部分,

Manacher演算法------求子串(Java)

最長迴文子串 對於一個字串,請設計一個高效演算法,計算其中最長迴文子串的長度。 給定字串A以及它的長度n,請返回最長迴文子串的長度。 測試樣例: "abc1234321ab",12 返回:7 public class Main {      public st

manacher演算法串)

這是建立部落格記錄的第一個程式碼。 題目解釋:     子串:小於等於原字串長度由原字串中任意個連續字元組成的子序列     迴文:關於中間字元對稱的文法,即“aba”(單核)、“cabbac”(雙核)等     最長迴文子串:1.尋找回文子串;2.該子串是迴文子串中

Manacher演算法串,時間複雜度O(n)

最長迴文子串 問題 對於一個字串,請設計一個高效演算法,計算其中最長迴文子串的長度。 給定字串A以及它的長度n,請返回最長迴文子串的長度。 測試樣例: “abc1234321ab”,12 返回:7 中心擴充套件到Manache

Hdu 3068 Manacher演算法串長度

最長迴文 Description 給出一個只由小寫英文字元a,b,c…y,z組成的字串S,求S中最長迴文串的長度. 迴文就是正反讀都是一樣的字串,如aba, abba等 Input 輸入有多組case,不超過120組,每組輸入為一行小寫英文字元a,b

manacher演算法

求最長迴文串可以使用manacher演算法來達到O(n)時間內得出結果,之所以降到O(n)是因為減少了很多重複匹配。 思路如下: 1.把所有字串都變成奇數個字母的串,方法很簡單,就是在所有字母前後加一個特殊字元,比如常用’#’,這樣長度為n的串就變成了長度為

Manacher演算法子串問題)

前言: 很久之前就聽到shallwe大爺提到過一種叫馬拉車的演算法。。。 問題描述 最長迴文子串問題:給定一個字串,求它的最長迴文子串長度 (注意,我們這裡說的子串一定是連續的,要與子序列區分開) 如果一個字串正著讀和反著讀是一樣的,那它就是迴文串

Manacher演算法解決子串問題---O(n)時間複雜度

#include <iostream> #include <string.h> using namespace std; void Manacher(char *src) { char *str = new char[2*strlen(src)+3]; str[0]

manacher演算法串 和 hdu 3068

1. 迴文串定義 迴文串是一個正讀和反讀都一樣的字串,比如“aba”或者“abba”等等就是迴文串。 2. 最長迴文子串方法 最長迴文子串的長度方法可以有三種方法: 1) 樸素演算法是依次以每一個字元為中心向兩側進行擴充套件,時間複雜度是O(N^2)的; 2) 利用

轉載-----Java Longest Palindromic Substring(字串)

轉載地址:https://www.cnblogs.com/clnchanpin/p/6880322.html 假設一個字串從左向右寫和從右向左寫是一樣的,這種字串就叫做palindromic string。如aba,或者abba。本題是這種,給定輸入一個字串。要求輸出一個子串,使得子串是最長的padromi

馬拉車演算法Manacher Algorithm)--用於計算子串

馬拉車演算法的目標是找到一串字串中的最長迴文子串,優點是時間複雜度為O(n) 現以尋找 “cgbaabgk” 中的最長子迴文串( “gbaabg”)為例進行說明 演算法過程(總共3步): 1.改造字串結構: 字元座標 0 1

【HDU - 3068】Manacher演算法,馬拉車演算法子串)

題幹: 給出一個只由小寫英文字元a,b,c...y,z組成的字串S,求S中最長迴文串的長度.  迴文就是正反讀都是一樣的字串,如aba, abba等 Input 輸入有多組case,不超過120組,每組輸入為一行小寫英文字元a,b,c...y,z組成的字串S  兩

Manacher馬拉車演算法求解子串

        馬拉車演算法是一種能在O(n)的時間複雜度範圍內得出結果。我看了不下幾次這個演算法,每次都覺得有點懂了,但是一碰到題目了,就生生寫不出來。歸根揭底,還是沒有掌握其思想。 馬拉車演算法的第一個核心思想就是往原始的字串裡填充一些輔助的東西,使得我們在考慮問題時不

字串演算法-Manacher’s Algorithm-馬拉車演算法

除了翻譯之外,其中還加入了個人的理解的部分,將其中沒有詳細說明的部分進行了解釋。 時間複雜度為O(n)的演算法 首先,我們需要講輸入的字串 S 進行一下轉換得到 T,轉換的方法就是通過在每兩個字元之間插入一個字串“#”,你馬上就能知道為什麼要這麼做。

字串--MANACHER演算法

個人感覺馬拉車演算法的思想和擴充套件KMP的思想是相似的。 首先對於這個問題,我們可以暴力列舉每個子串,然後判斷是否是迴文串,時間複雜度大概是O(n^3),我們運用下尺取法的思想,列舉每一個對稱軸位置(針對長度的奇偶有所區別),那麼時間複雜度會是O(n^2),接著我們如果把

Manacher演算法:求解字串,時間複雜度為O(N)

迴文串定義:“迴文串”是一個正讀和反讀都一樣的字串,比如“level”或者“noon”等等就是迴文串。迴文子串,顧名思義,即字串中滿足迴文性質的子串。 經常有一些題目圍繞回文子串進行討論,比如POJ3974最長迴文,求最長迴文子串的長度。樸素演算法是依次以每一個字元為中心

【探索-中級演算法子串

這一題可以參考:647. 迴文子串 本質上是一樣的,要判斷出所有的迴文字串,然後找到其中最長的那一個。 中心擴充套件法 中心擴充套件就是把給定的字串的每一個字母當做中心,向兩邊擴充套件,這樣來找最長的子迴文串。演算法複雜度為O(N^2) public Stri

馬拉車演算法(求子串)

1 #include <vector> 2 #include <iostream> 3 #include <string> 4 5 using namespace std; 6 7 string Manacher(string s) {

資料結構演算法題/子串

迴文表示字串正向和反向是相同的。例如a, aba, abccba 一、暴力法 最容易想到的就是暴力破解,求出每一個子串,之後判斷是不是迴文,找到最長的那個。 求每一個子串時間複雜度O(N^2), 判斷子串是不是迴文O(N),兩者是相乘關係,所以時間複雜度為O(N^3)。 二、動態規劃

leetcode-中級演算法-陣列和字串-字串

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。 示例 1: 輸入: “babad” 輸出: “bab” 注意: "aba"也是一個有效答案。 示例 2: 輸入: “cbbd” 輸出: “bb” 思路 這道題很顯然可以用暴力求解,但時