動態規划——最長回文子串


  最長回文子串的問題描述:

 

  下面介紹動態規划的方法,使用動態規划可以達到最優的 O(n2) 復雜度。

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

    1.  若 S[i] == S[j],那么只要 S[i+1] 至 S[j-1] 是回文子串,S[i] 至 S[j] 就是回文子串;如果S[i+1] 至 S[j-1] 不是回文子串,則 S[i] 至 S[j] 也不是回文子串。
    2.  若 S[i] != S[j],那么 S[i] 至 S[j] 一定不是回文子串。    

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

          $dp[i][j]=\left\{\begin{matrix}dp[i+1][j-1],S[i]==S[j]\\ 0,S[i]!=S[j]\end{matrix}\right.$

  邊界:dp[i][i]=1,dp[i][i+1] = (S[i] == S[i+1]) ? 1 : 0。

  根據遞推寫法從邊界出發的原理,注意到邊界表示的是長度為 1 和 2 的子串,且每次轉移時都對子串的長度減了 1,因此不妨考慮按子串的長度和子串的初始位置進行枚舉,即第一遍將長度為 3 的子串的 dp 值全部求出,第二遍通過第一遍結果計算出長度為 4 的子串的 dp 值 ……

  代碼如下:

 1 /*
 2     最長回文子串 
 3 */
 4 
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <math.h>
 8 #include <stdlib.h>
 9 #include <time.h>
10 #include <stdbool.h>
11 
12 #define maxn 1010
13 char S[maxn];
14 int dp[maxn][maxn];                 
15 
16 int main() {
17     gets(S);                        // 輸入整行字符 
18     int len=strlen(S), ans=1;        // ans 記錄最長回文子串長度 
19     int i, j, L;        
20     // 邊界 
21     for(i=0; i<len; ++i) {            
22         dp[i][i] = 1;
23         if(i < len-1) {
24             if(S[i] == S[i+1]) {
25                 dp[i][i+1] = 1;
26                 ans = 2;
27             }
28         }
29     }
30     // 狀態轉移方程 
31     for(L=3; L<=len; ++L) {            // 枚舉子串長度 
32         for(i=0; i+L-1 < len; ++i) {    // 枚舉子串的起始節點 
33             j = i+L-1;                // 子串的右端結點 
34             if(S[i]==S[j] && dp[i+1][j-1]==1) {
35                 dp[i][j] = 1;
36                 ans = L;            // 更新最長回文子串長度 
37             }
38         }
39     }
40     printf("%d\n", ans);            // 輸出 
41 
42     return 0;
43 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM