問題:給出乙個字串s,求s的最長回文子串的長度。
結果:字串"patzjujztaccbcc"的最長回文子串為"atzjujzta",長度為9。
暴力解法
列舉子串的兩個端點i和j,判斷在[i, j]區間內的子串是否回文。從複雜度上來看,列舉端點需要0(n2),判斷回文需要0(n),因此總複雜度是o(n3)。
動態規劃解決
令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]至s[j]就是回文子串;如果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][j - 1]已經被計算過,從而無法得到正確的dp[i][i]。
如圖11-4所示,先固定i=0,然後列舉j從2開始。當求解dp[0][2]時,將會轉換為dp[1][1],而dp[1][1]是在初始化中得到的;當求解dp[0][3]時,將會轉換為dp[1][2], 而dp[1][2]也是在初始化中得到的;當求解dp[0][4]時,將會轉換為dp[1][3], 但是dp[1][3]並不是已經計算過的值,因此無法狀態轉移。事實上,無論對i和j的列舉順序做何調整,都無法調和這個矛盾,因此必須想辦法尋找新的列舉方式。
根據遞推寫法從邊界出發的原理,注意到邊界表示的是長度為1和2的子串,且每次轉移時都對子串的長度減了1,因此不妨考慮按子串的長度和子串的初始位置進行列舉,即第一遍將長度為3的子串的dp值全部求出,第二遍通過第一遍結果計算出長度為4的子串的dp值…這樣就可以避免狀態無法轉移的問題。如圖11-5所示,可以先列舉子串長度l (注意: l是可以取到整個字串的長度s.len()的),再列舉左端點i,這樣右端點i+ l- 1也可以直接得到。
//狀態轉移方程
for (int l = 3; l <= length; l++) }}
system.out.println("最長回文子串長度:" + maxsubmirrorstrlength);
}}
動態規劃之最長回文子串
問題 給出乙個字串s,求s的最長回文子串的長度。樣例 字串 patzjujztaccbcc 的最長回文子串為 atzjujzta 長度為9。還是先看暴力解法 列舉子串的兩個端點i和j,判斷在 i,j 區間內的子串是否回文。從複雜度上來看,列舉端點需要0 n2 判斷回文需要0 n 因此總複雜度是o n...
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。這很顯然,每個單獨的字元其實就是個長度...