摘要:若他的子串為回文串,則相對于對稱的另一端子串必然是回文串?;匚拇囟ㄊ侵行膶ΨQ的,也就是。目前確定的是回文半徑范圍內(nèi)能確定的值,對于半徑外的字符因為不知能能否和已知回文串繼續(xù)構(gòu)成更大回文串,所以也要進行判斷。
今天思考一道題的時候,學(xué)習(xí)了一些思路,其中 Manacher 算法很有必要記錄下來。
本文參考了:http://blog.csdn.net/ggggiqny...
這道題的內(nèi)容是:
給定字符串,找到它的最長回文子串
最簡單的思路莫過于找到給定字符串的所有子字符串,然后一個個的判斷他們是否是回文字符串,在判斷的時候用一個變量把最長的回文字符串記錄下來就可以了;
判斷是不是回文字符串很容易
function isPalindrome(str) { var newStr = str.split("").reverse().join(""); return newStr === str ? true : false; }
獲得所有子串也很容易
function getSubstring(str){ var len = str.length; for(var i=0; i這種簡單粗暴的算法帶來的后果就是:查找子串時間復(fù)雜度O(n^2),判斷回文時間復(fù)雜度O(n),太費時間;浪費時間的主要原因是沒有充分地利用獲得的信息。
————————————————————分界線————————————————————————
Manacher算法非常巧妙,使用了一些輔助技巧使得整個算法的時間復(fù)雜度變?yōu)榫€性。
我們先明確兩件事:一個字符串是回文字符串,其中間位置為m。若他的子串S[i,i+x]為回文串,則相對于m對稱的另一端子串S[2m-i, 2m-(i+x)]必然是回文串。
回文串必定是中心對稱的,也就是:S[i] == S[2m-i]。
首先,Manacher算法使用了如下的一個技巧讓我們不用考慮字符串的奇偶性問題:
每一個字符兩邊都加上一個特殊字符,比如以字符串"abba"為例,轉(zhuǎn)換后變成"#a#b#b#a#"。這樣一來字符串無論本來是奇數(shù)還是偶數(shù),都會變成奇數(shù)。function getNewString(str){ var newStr = "#"; for(i = 0;i然后設(shè)置了一個概念:創(chuàng)建一個新數(shù)組P, P[i]項表示以第i個字符為中心的回文字串的半徑。比如
S # a # b # b # a # P 1 2 1 2 5 2 1 2 1通過表格可以發(fā)現(xiàn),P[i]-1就是實際回文字串的長度(對應(yīng)的是符號還是數(shù)字都沒關(guān)系)。
所以我們的任務(wù)轉(zhuǎn)化為了求解數(shù)組 P;
求解數(shù)組 P 是本算法核心,根據(jù)我的理解,將其概括為如下:
設(shè)置兩個輔助參數(shù):id 和 mx;id表示當前已記載過的邊界最大的回文字符串的中心位置,mx此回文字符串的邊界值,也就是id+p[i];
初始化一便數(shù)組P,以避免數(shù)組中有undefined:for(i = 0;i接下來開始討論:
記 i 對應(yīng)于中心點 id 的對應(yīng)位置為j,即j = 2*id - i;
若當前已記載的最大邊境 mx > i(即 i 位置對應(yīng)的字符在已知回文字符串內(nèi)),那么:p[i] = Math.min(p[j], mx-i);就是當前面比較的最遠長度 mx > i 的時候,P[i]有一個最小值,這就是本算法最核心的性質(zhì)。
目前確定的P[i]是回文半徑范圍內(nèi)能確定的值,對于半徑外的字符,因為不知能能否和已知回文串繼續(xù)構(gòu)成更大回文串,所以也要進行判斷。
while ((newStr[i + p[i]] == newStr[i - p[i]]) && newStr[i + p[i]]){ p[i]++; }最后一步,當有更大的回文串出現(xiàn)時,更新mx 和 id 的值
if (i + p[i] > mx) { id = i; mx = id + p[i]; }整體代碼function getArrayP(str){ var p = [], mx = 0, id = 0; var i; var newStr = "#"; // 將字符串轉(zhuǎn)化為奇數(shù)長度獲取到新的字符串 var len = str.length; for(i = 0;ii ? Math.min(p[2*id-i], mx-i) : 1; while ((newStr[i + p[i]] == newStr[i - p[i]]) && newStr[i + p[i]]){ // 超出其半徑的位置再做額外判斷,確保 newStr[i + p[i]] 是存在的 p[i]++; } // 當有更大的回文串出現(xiàn)時,更新中心位置和最大邊界值 if (i + p[i] > mx) { id = i; mx = id + p[i]; } } return p; } 獲得數(shù)組 p 之后,我們就獲取到P的最大值,上面的例子中,最大值是 p[4] = 5;因為回文半徑算了自己在內(nèi),所以要減去1,所以回文字符串應(yīng)該是從newStr[4-4]起,到newStr[4+4]為止。用newStr.subString(0,8)方法獲得字符串后,再去掉『#』符號就可以了;
newstr.subString(0, 8).split("#").join("");
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86908.html
摘要:問題定義最長回文子串問題給定一個字符串,求它的最長回文子串長度??梢圆捎脛討B(tài)規(guī)劃,列舉回文串的起點或者終點來解最長回文串問題,無需討論串長度的奇偶性。 0. 問題定義 最長回文子串問題:給定一個字符串,求它的最長回文子串長度。 如果一個字符串正著讀和反著讀是一樣的,那它就是回文串。下面是一些回文串的實例: 12321 a aba abba aaaa tatt...
摘要:題目即求最長回文子序列原題鏈接此篇博客僅為學(xué)習(xí)記錄我的解法及代碼暴力解決,用及進行兩層遍歷循環(huán)中套一層循環(huán),用遍歷,求最長回文序列字符串,同時用變量記錄最長子序列這種寫法很暴力,效率很低,一層循環(huán),一層循環(huán),回文序列對比一層,時間復(fù)雜度為辣 題目: Given a string s, find the longest palindromic substring in s. You ma...
摘要:這種解法中,外層循環(huán)遍歷的是子字符串的中心點,內(nèi)層循環(huán)則是從中心擴散,一旦不是回文就不再計算其他以此為中心的較大的字符串。 Longest Palindromic Substring Given a string S, find the longest palindromic substring in S. You may assume that the maximum length ...
摘要:通過使用,我們將無論是奇數(shù)還是偶數(shù)的回文串,都變成了一個以為中心,為半徑兩個方向擴展的問題。并且就是回文串的長度。 Given a string s, find the longest palindromic substring in s. 這題的意思是找出 最長連續(xù)回文串。 思路來源于此 這里描述了一個叫Manacher’s Algorithm的算法。 算法首先將輸入字符串S, 轉(zhuǎn)換...
閱讀 1315·2021-11-15 11:37
閱讀 3504·2021-11-11 16:55
閱讀 1756·2021-08-25 09:39
閱讀 3220·2019-08-30 15:44
閱讀 1735·2019-08-29 12:52
閱讀 1409·2019-08-29 11:10
閱讀 3244·2019-08-26 11:32
閱讀 3227·2019-08-26 10:16