序列最的問題之最長公共子序列LCS

  在程序設計競賽中,咱們時常會遇到序列求最值的問題。在講今天的問題以前,先小小的說明一下,子序列與子串的問題。ios

  子序列:在原序列中不必定連續;數組

  子串:在原序列中必須連續。ide

  接下來,就開始今天要講的最長公共子序列LCS(Longest Common Subsequence).對於LCS這一類的問題,通常是相對於兩個序列而言,str[]與ch[]。先假設str的長度爲n,ch的長度爲m。假設str[]="ASBDAH",ch[]="SDAAH";其中"SDA"是其中的str與ch的一個子序列,但不是最長的。最長的子序列爲"SDAH",固然,有時候咱們會看到兩個串中有多個相同長度的子序列,這不足爲奇。spa

  若是咱們枚舉str的子序列,那麼將有2n個子序列,這很不切實際。所以咱們能夠試着讓str中前1,2,3……n參與的狀況下分別與ch串中前1,2……m參與狀況求出LCS。設計

  

  dp[i][j]表示str前i個參與,以及ch前j個參與的LCS。code

  當str[i] == ch[j]時,只須要記錄統計出str[1~i - 1],ch[1~j - 1]的LCS,在此基礎上加1.blog

  當str[i] != ch[j]時,咱們只須要求str[1 ~ i - 1]且ch[1~j],str[1 ~ i]且ch[1~j-1]的最大值便可。get

  

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <math.h>
 5 using namespace std;
 6 const int MAX = 100 + 10;
 7 char str[MAX], ch[MAX];
 8 int dp[MAX][MAX];
 9 
10 int max(int a, int b){ return a > b ? a : b;}
11 
12 int main()
13 {
14     int t, n, m;
15     scanf("%d", &t);
16     getchar();
17 
18     while (t--)
19     {
20         scanf("%s%s", str, ch);
21         n = strlen(str);
22         m = strlen(ch);
23 
24         for (int i = 0; i < n; i++)
25         {
26             for (int j = 0; j < m; j++)
27             {
28                 if (str[i] == ch[j])
29                 {
30                     dp[i + 1][j + 1] = dp[i][j] + 1;
31                 }
32                 else dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
33             }
34         }
35 
36         printf("%d\n", dp[n][m]);
37 
38     }
39 
40     return 0;
41 }
View Code
  若是,僅僅想獲得結果,咱們還能夠將空間壓縮一下。因爲每次都以後用到i,i-1這兩行數據,因此咱們能夠使用滾動數組。因爲動態規劃保證無後效性,因此咱們徹底能夠使用一維數組。琢磨一下……
  相反若是咱們想輸出該序列呢,咱們也徹底能夠加一個輔助數組flag[][].當str[i] == ch[j],flag[i][j] = 0,若是dp[i - 1][j] > dp[i][j - 1],flag[i][j] = 1,反之,flag[i][j] = 2;以此來記錄起路徑,最後從flag[n][m]開始往回找。
相關文章
相關標籤/搜索