動態規劃之最長回文子串

2021-09-19 16:21:12 字數 1875 閱讀 2527

問題:

給出乙個字串s,求s的最長回文子串的長度。
樣例

字串"patzjujztaccbcc"的最長回文子串為"atzjujzta",長度為9。
還是先看暴力解法:列舉子串的兩個端點i和j,判斷在[i, j]區間內的子串是否回文。從複雜度上來看,列舉端點需要0(n2),判斷回文需要0(n),因此總複雜度是o(n3)。終於碰到乙個暴力複雜度不是指數級別的問題了!但是o(n)的複雜度在n很大的情況依舊不夠看。

可能會有讀者想把這個問題轉換為最長公共子串行(lcs) 問題來求解:把字串s倒過來變成字串t,然後對s和t進行lcs模型求解,得到的結果就是需要的答案。而事實上這種做法是錯誤的,因為一旦s中同時存在乙個子串和它的倒序,那麼答案就會出錯。例如字串s= 「abcdzjudcba」,將其倒過來之後會變成t = 「abcdujzdcba」,這樣得到最長公共子串為"abcd",長度為4,而事實上s的最長回文子串長度為1。因此這樣的做法是不行的。

動態規劃解決

令dp[i][j]表示s[i]至s[j]所表示的子串是否是回文子串,是則為1,不是為0。這樣根據s[i]是否等於s[j],可以把轉移情況分為兩類:

①若s[i]=s[j],那麼只要s[i+1]和s[j-1]是回文子串,s[i+1]至s[j-1]就是回文子串;如果s[i+1]至s[j-1]不是回文子串,則s[i]至s[j]一定不是回文子串。

②若s[i]!=s[j],那s[i]至s[j]一定不是回文子串。

由此可以寫出狀態轉移方程

邊界dp[i][i]=1,dp[i][i+1]=(s[i]==s[i+1])?1:0 。
到這裡還有乙個問題沒有解決,那就是如果按照i和j從小到大的順序來列舉子串的兩個端點,然後更新dp[i]lj],會無法保證dp[i + 1][ - 1]已經被計算過,從而無法得到正確的dp[i][i]。

如圖11-4所示,先固定i=0,然後列舉j從2開始。當求解dp[0][2]時,將會轉換為dp[1],而dp[1][1]是在初始化中得到的;當求解dp[0][3]時,將會轉換為dp[1][2], 而dp[1][2]也是在初始化中得到的;當求解dp[0][4]時,將會轉換為dp[1][3], 但是dp[1][3]並不是已經計算過的值,因此無法狀態轉移。事實上,無論對ij和j的列舉順序做何調整,都無法調和這個矛盾,因此必須想辦法尋找新的列舉方式。

根據遞推寫法從邊界出發的原理,注意到邊界表示的是長度為1和2的子串,且每次轉移時都對子串的長度減了1,因此不妨考慮按子串的長度和子串的初始位置進行列舉,即第一遍將長度為3的子串的dp值全部求出,第二遍通過第一遍結果計算出長度為4的子串的dp值…這樣就可以避免狀態無法轉移的問題。如圖11-5所示,可以先列舉子串長度l (注意: l是可以取到整個字串的長度s.len()的),再列舉左端點i,這樣右端點i+ l- 1也可以直接得到。

char s[maxn];//a存序列,dp[i]存以i為結尾的連續序列的最大和

int dp[maxn][maxn];

int main()

} }//狀態轉移方程

for(int l=3;l<=len;l++)//列舉子串長度

for(int i=0;i+l-1

本身,所以要-1)必須小於總長,

}cout<

}

動態規劃之最長回文子串

問題 給出乙個字串s,求s的最長回文子串的長度。結果 字串 patzjujztaccbcc 的最長回文子串為 atzjujzta 長度為9。暴力解法 列舉子串的兩個端點i和j,判斷在 i,j 區間內的子串是否回文。從複雜度上來看,列舉端點需要0 n2 判斷回文需要0 n 因此總複雜度是o n3 動態...

LeetCode動態規劃之最長回文子串

給定乙個字串s,找到s中最長的回文子串。你可以假設s的最大長度為 1000。輸入 babad 輸出 bab 注意 aba 也是乙個有效答案。輸入 cbbd 輸出 bb 首先,必須要明確最長回文子串的含義,簡單來說就是 從前往後讀和從後往前讀 是一樣的,按照我們動態規劃解題3步驟 定義陣列元素含義,找...

動態規劃之最長回文串

dp i j 表示 以s i 開始s j 結尾的回文串的長度。如果這個字串不是回文串,讓dp i j 0 顯然,j i,只需往dp填j i的部分即可。dp i j 的遞推公式可以這麼表述 1 首先對dp的對角線元素初始化為1,也就是當i j時,dp i j 1。這很顯然,每個單獨的字元其實就是個長度...