日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

lintcode最长回文子串(Manacher算法)

發(fā)布時(shí)間:2025/3/8 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 lintcode最长回文子串(Manacher算法) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目來自lintcode, 鏈接:http://www.lintcode.com/zh-cn/problem/longest-palindromic-substring/

最長回文子串?

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

樣例

給出字符串?"abcdzdcab",它的最長回文子串為?"cdzdc"。

挑戰(zhàn)

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

?

一. 首先給出O(n^2)的算法

思路:dp[i][k]表示第i個(gè)位置開始長度為k的串的最大回文串的長度, j=i+k-1

   ? 當(dāng)?s[i] == s[j] && dp[i+1][k-2] == k-2, ?dp[i][k] = dp[i+1][k-2] + 2;

   ? 否則 ?dp[i][k] = max(dp[i+1][k-1], dp[i][k-1]);

   ? 并記錄dp[i][k]的最大值,最后找到最長回文子串的區(qū)間。

int dp[1005][1005];string longestPalindrome(string& s) {// Write your code hereO(n^2)int len = s.size();memset(dp, 0, sizeof(dp));for(int i=0; i<len; ++i)dp[i][1] = 1;int ld=0, rd=0, maxL = 1;for(int k=2; k<=len; ++k){for(int i=0, j; i<len && (j=i+k-1)<len; ++i){if(s[i] == s[j] && dp[i+1][k-2] == k-2)dp[i][k] = dp[i+1][k-2] + 2;else dp[i][k] = max(dp[i+1][k-1], dp[i][k-1]);if(maxL<dp[i][k]){maxL = dp[i][k];ld = i;rd = j;}}}return s.substr(ld, rd-ld+1);
}

二.然后看一下復(fù)雜度為O(n)的Manacher算法

2.1 先說一下這個(gè)算法的思想:

  用一個(gè)數(shù)組 P[i] 來記錄以字符S[i]為中心的最長回文子串向左/右擴(kuò)張的長度(包括S[i])。

2.2 算法基本要點(diǎn):

  這個(gè)算法不能求出最長回文串長度為偶數(shù)回文串。用一個(gè)非常巧妙的方式,將所有可能的奇數(shù)/偶數(shù)長度的回文子串都轉(zhuǎn)換成了奇數(shù)長度:在相鄰兩個(gè)字符之間插入一個(gè)特殊的符號(hào)。比如 abba 變成 a#b#b#a。 為了進(jìn)一步減少編碼的復(fù)雜度,可以在字符串的開始加入另一個(gè)特殊字符,這樣就不用特殊處理越界問題,比如$a#b#b#a。

2.3 具體說一個(gè)例子:

  S[] ? ? 1? #? 2? #? 2? #? 1? #? 2? #? 3? #? 2? #? 1
  P[] ? ? 1 ?1 ? 2 ?1 ?2 ? 1 ?4 ?1 ?2 ?1 ?5 ?1 ? 2 ?1 ?1
  (p.s. 可以看出,P[i]-1正好是原字符串中回文串的總長度)

2.4 為啥要對(duì)字符串進(jìn)行處理(插入'#')

如果不對(duì)字符進(jìn)行處理, 對(duì)于最長回文串為偶數(shù)的情況下:

  S[] ? ? 1 ?2 ?1 ?1 ?2 ?1
  P[] ? ? 1 ?2 ?1 ?1 ?2 ?1

對(duì)字符進(jìn)行處理,對(duì)于最長回文串為偶數(shù)的情況下:

  S[] ? ? 1 ?# ?2 ?# ?1 ?# ?1 ?# ?2 ?# ?1
  P[] ? ? 1 ?1 ? 3 ?1 ?2 ?6 ? 2 ?1 ?3 ?1 ?1

可見不對(duì)字符進(jìn)行處理,對(duì)于最長回文串為偶數(shù)的情況是不能得到最大的回文串的長度。

2.5 如何計(jì)算P數(shù)組的值:

  算法增加兩個(gè)輔助變量id和mx,其中id表示最大回文子串中心的位置,mx則為id+P[id],也就是最大回文子串的邊界。

  當(dāng) mx - i > P[j] 的時(shí)候,以S[j]為中心的回文子串包含在以S[id]為中心的回文子串中,由于 i 和 j 對(duì)稱,以S[i]為中心的回文子串必然包含在以S[id]為中心的回文子串中,所以必有 P[i] = P[j],見下圖。

              

  當(dāng) P[j] > mx - i 的時(shí)候以S[j]為中心的回文子串不完全包含于以S[id]為中心的回文子串中,但是基于對(duì)稱性可知,下圖中兩個(gè)綠框所包圍的部分是相同的,也就是說以S[i]為中心的回文子串,其向右至少會(huì)擴(kuò)張到mx的位置,也就是說 P[i] >= mx - i。至于mx之后的部分是否對(duì)稱,就只能一個(gè)一個(gè)匹配了。

              

  對(duì)于 mx <= i 的情況,無法對(duì) P[i]做更多的假設(shè),只能P[i] = 1,然后再去匹配了。

2.6 尋找最大長度的回文子串:

  看一種情況:

    S[] ? ? 1 ?# ?2 ?# ?2 ?
    P[] ? ? 1 ?1 ? 2 ?2 ?1?

  首先, P中的最大值為2,但是最大值有兩個(gè),我們應(yīng)該選擇哪一個(gè)?其實(shí),如果P中的最大值對(duì)應(yīng)的字符不是'#',顯然不能得到最大長度的回文串。所以當(dāng)我們遇到這種情況時(shí)(maxP == P[i] && S[i]=='#')要更新最大值所在位置。

2.7 最后代碼:

class Solution { public:/*** @param s input string* @return the longest palindromic substring*/string manacher(string& str){int *p = new int[str.size()]();memset(p, 0, sizeof(p));int mx = 0, id = 0;for(int i=1; i<str.size(); i++){if(mx > i)p[i] = min(p[2*id-i], mx-i);elsep[i] = 1;while(str[i - p[i]] == str[i + p[i]])++p[i];if(i + p[i] > mx){mx = i + p[i];id = i;}}//尋找數(shù)組P中的最大值的位置int maxP = 0;for(int i=1; i<str.size(); ++i)if(maxP < p[i] || (maxP == p[i] && str[i]=='#')){maxP = p[i];id = i;} //根據(jù)id,確定最長回文串的區(qū)間int ld = id-p[id]+1, rd = id+p[id]-1;string ans = "";for(int i=ld; i<=rd; ++i)if(str[i]!='#')ans += str[i];return ans;}string longestPalindrome(string& s) {// Write your code here//采用manacher算法,O(n)的時(shí)間復(fù)雜度int len = s.size();
//首先預(yù)處理字符串,每?jī)蓚€(gè)字符之間插入'#'
int k = -1;for(int i=1; i<len; ++i)s.insert(k+=2, 1, '#');s.insert(0, 1, '$');return manacher(s);} };

?

轉(zhuǎn)載于:https://www.cnblogs.com/hujunzheng/p/5033891.html

總結(jié)

以上是生活随笔為你收集整理的lintcode最长回文子串(Manacher算法)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。