LCS

思路:ios

  明顯的能夠想到,狀態轉移方程爲:數組

  當x[i] == y[j]時,dp[i][j] = dp[i-1][j-1]+1優化

  當x[i] != y[j]時,dp[i][j] = max(dp[i-1][j], dp[i][j-1])spa

  這種方法能夠結合下面的決策矩陣和代碼加深理解(參考自https://blog.csdn.net/linraise/article/details/9104975.net

  

 

 1 #include<iostream>
 2 using namespace std;
 3 #define M 7
 4 #define N 6
 5 int b[M + 1][N + 1] = {0}; //存方向
 6 int c[M + 1][N + 1] = {0}; //存值
 7 
 8 void Lcs_Length(char *X, char *Y)
 9 {
10     int i, j;
11     for(i = 1; i <= M; i++)
12         c[i][0] = 0;
13     for(j = 0; j <= N; j++)
14         c[0][j] = 0;
15     for(i = 1; i <= M; i++)
16     {
17         for(j = 1; j <= N; j++)
18         {
19             if(X[i] == Y[j]) //比較兩個字串對應位,若是相等,則=對角+1
20             {
21                 c[i][j] = c[i - 1][j - 1] + 1;
22                 b[i][j] = 1; //1表明↖ 
23             }
24             else if(c[i - 1][j] >= c[i][j - 1]) //若是上面值>=下面值
25             {
26                 c[i][j] = c[i - 1][j]; //c[i][j]=大值
27                 b[i][j] = 2; //2表明↑
28             }
29             else
30             {
31                 c[i][j] = c[i][j - 1]; //賦的老是大值,箭頭老是指向大值
32                 b[i][j] = 3; //3表明←
33             }
34         }
35     }
36 }
37 void Print_Lcs(char *X, int i, int j)
38 {
39     if(i == 0 || j == 0)
40         return ;
41     if(b[i][j] == 1)
42     {
43         Print_Lcs(X, i - 1, j - 1);
44         cout << X[i] << ' '; //只需輸出↖對應的值
45     }
46     else if(b[i][j] == 2)
47         Print_Lcs(X, i - 1, j);
48     else Print_Lcs(X, i, j - 1);
49 }
50 int main()
51 {
52     char  X[M + 1] = {'0', 'A', 'B', 'C', 'B', 'D', 'A', 'B'};
53     char  Y[N + 1] = {'0', 'B', 'D', 'C', 'A', 'B', 'A'};
54     Lcs_Length(X, Y);
55     Print_Lcs(X, M, N);
56     cout << endl;
57     for(int i = 0; i <= M; i++)
58     {
59         for(int j = 0; j <= N; j++)
60         {
61             cout << c[i][j] << ' ';
62         }
63         cout << endl;
64     }
65     cout << endl;
66     for(int i = 0; i <= M; i++)
67     {
68         for(int j = 0; j <= N; j++)
69         {
70             switch(b[i][j])
71             {
72             case 0:
73             {
74                 cout << b[i][j] << "  ";
75                 break;
76             }
77             case 1:
78             {
79                 cout << '\\' << ' ' << ' ';
80                 break;
81             }
82             case 2:
83             {
84                 cout << '|' << ' ' << ' ';
85                 break;
86             }
87             case 3:
88             {
89                 cout << '-' << ' ' << ' ';
90                 break;
91             }
92             }
93         }
94         cout << endl;
95     }
96     return 0;
97 }

 

進一步分析:code

  這種動態規劃作法,用空間換取時間,對比暴力法,時間複雜度由O(m2n2)下降到了O(n2),那麼有沒有什麼方法能進一步優化空間複雜度呢?答案是確定的。分析上面的決策矩陣,發現每一行的值都是由上一行決定的,因此前面行的值是能夠捨棄,沒必要保存的,這就能夠使用滾動數組進行空間優化。blog

for(i = 1; i <= m; i++)
{
    for(j = 1; j <= n; j++)
    {
        if(x[i] == y[j])
            dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1;
        else if(dp[(i - 1) % 2][j] >= dp[i % 2][j - 1])
            dp[i % 2][j] = dp[(i - 1) % 2][j];
        else
            dp[i % 2][j] = dp[i % 2][j - 1];
    }
}

   那麼O(n2)的時間複雜度能繼續優化嗎?答案也是確定的。作法是將LCS問題轉換成O(nlogn)的LIS問題來求解,後續補充~get

 reference:it

https://blog.csdn.net/linraise/article/details/9104975io

相關文章
相關標籤/搜索