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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

字符串系列之最长回文子串

發(fā)布時間:2023/11/29 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符串系列之最长回文子串 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

問題描述:

? ? 給定一個字符串S=A1A2...An,要求找出其最長回文子串(Longest Palindromic Substring)。所謂回文子串就是S的某個子串Ai...Aj為回文。例如,對字符串S=abcdcbeba,它的回文子串有:bcdcb,cdc,beb,滿足題目要求的最長回文子串為bcdcb。

推理思路:

1.由于回文可能由奇數(shù)個字符組成,也可能由偶數(shù)個字符組成。對奇數(shù)回文的處理比較直觀,只需要以某個字符為中心,依次向兩邊擴(kuò)展即可。因此,我們可以通過如下方式把對偶數(shù)回文的處理轉(zhuǎn)換成對奇數(shù)回文的處理:在字符邊界添加特殊符號。例如,對字符串a(chǎn)ba,預(yù)處理后變成#a#b#a#;對字符串a(chǎn)bba,預(yù)處理后變成#a#b#b#a??梢钥闯?#xff0c;不管是奇數(shù)回文,還是偶數(shù)回文,在與處理后都變成奇數(shù)回文。在找出與預(yù)處理后字符串的最長回文后,只需要去除所有的#即為源字符串的最長回文。

2.對尋找字符串某類子串的問題,最簡單直觀的想法就是窮舉出所有子串一一進(jìn)行判別。這里也不例外,當(dāng)然時間復(fù)雜度也很高,為O(n^3)。

3.對該問題,我們可以進(jìn)行一定程度的簡化處理。既然回文是一種特殊的字符串,我們可以以源字符串的每個字符為中心,依次尋找出最長回文子串P0, P1,...,Pn。這些最長回文子串中的最長串Pi = max(P1, P2,...,Pn)即為所求。請看源碼:

string?find_lps_native(const?string?&str) {int?center?=?0,?max_len?=?0;for(int?i?=?1;?i?<?str.length()-1;?++i){int?j?=?1;//以str[i]為中心,依次向兩邊擴(kuò)展,尋找最長回文Piwhile(i+j?<?str.length()?&&?i-j?>=?0?&&?str[i+j]?==?str[i-j])++j;--j;if(j?>?1?&&?j?>?max_len){center?=?i;max_len?=?j;}}return?str.substr(center-max_len,?(max_len?<<?1)?+?1); }

4.可以看出,上面做法的復(fù)雜度為O(n^2)。相比窮舉字符串的做法,已經(jīng)降低了一個量級的復(fù)雜度。但是仔細(xì)想想,上面的算法還有改進(jìn)空間嗎?當(dāng)然有!而且改進(jìn)后能夠把復(fù)雜度降低到O(n)!這就是大名鼎鼎的 Manacher’s Algorithm。請看下文分析:

? ? 舉例說明:對字符串S=abcdcba而言,最長回文子串是以d為中心,半徑為3的子串。當(dāng)我們采用上面的做法分別求出以S[1]=a, S[2]=b, S[3]=c, S[4]=d為中心的最長回文子串后,對S[5]=c,S[6]=b...還需要一一進(jìn)行擴(kuò)展求嗎?答案是NO。因?yàn)槲覀円呀?jīng)找到以d為中心,半徑為3的回文了,S[5]與S[3],S[6]與S[2]...,以S[4]為對稱中心。因此,在以S[5],S[6]為中心擴(kuò)展找回文串時,可以利用已經(jīng)找到的S[3],S[2]的相關(guān)信息直接進(jìn)行一定步長的偏移,這樣就減少了比較的次數(shù)(回想一下KMP中next數(shù)組的思想)。優(yōu)化的思想找到了,我們先看代碼:

string?find_lps_advance(const?string?&str) {//find?radius?of?all?charactersvector<int>?p(str.length(),?0);int?idx?=?1,?max?=?0;for(int?i?=?1;?i?<?str.length()-1;?++i){if(max?>?i){p[i]?=?p[(idx?<<?1)?-?i]?<?(max?-?i)???p[(idx?<<?1)?-?i]:(max?-?i);}while(str[i+p[i]+1]?==?str[i-p[i]-1])p[i]?+=?1;if(i?+?p[i]?>?max){idx?=?i;max?=?i+p[i];}}//?find?the?character?which?has?max?radiusint?center?=?0,?radius?=?0;for(int?i?=?0;?i?<?p.size();?++i){if(p[i]?>?radius){center?=?i;radius?=?p[i];}}return?str.substr(center-radius,?(radius?<<?1)?+?1); }

? ? 這里進(jìn)行簡單的解釋:上述代碼中有三個主要變量,它們代表的意義分別是:

? ? ?p:以S[i]為中心的最長回文串的半徑為p[i]。

? ? ?idx:已經(jīng)找出的能夠右延伸最遠(yuǎn)距離的回文子串的起始位置。

? ? ?max:已經(jīng)找出的能夠右延伸最遠(yuǎn)距離的回文子串的結(jié)束位置。

? ? ?算法的主要思想是:先找出所有的p[i],最大的p[i]即為所求。在求p[j] (j>i)時,利用已經(jīng)求出的p[i]減少比較次數(shù)。

? ? ?代碼中比較關(guān)鍵的一句是:

?p[i]?=?p[(idx?<<?1)?-?i]?<?(max?-?i)???p[(idx?<<?1)?-?i]:(max?-?i);

? ? 在求p[i]時,如果max>i,則表明已經(jīng)求出的最長回文中包含了p[i],那么與p[i]關(guān)于idx對稱的p[ (idx << 1) - i]的最長回文子串可以提供一定的信息??戳藘煞鶊D大概就明白什么意思了:

? ? 求二者的最小值是因?yàn)楫?dāng)前能夠獲取的信息都來自max的左側(cè),需要進(jìn)一步比較,求出以S[i]為中心的最長回文串。

5.除了上述的幾種做法外,還可以利用動態(tài)規(guī)劃以及后綴樹來進(jìn)行求解。下次進(jìn)行介紹。

? ? 結(jié)束行文之前,補(bǔ)充一句,對于字符串類的問題,建議多畫一畫,尋找其中的規(guī)律。

?

參考文獻(xiàn):1.http://www.akalin.cx/longest-palindrome-linear-time

?

轉(zhuǎn)載于:https://my.oschina.net/pathenon/blog/63575

總結(jié)

以上是生活随笔為你收集整理的字符串系列之最长回文子串的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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