最長公共子串行(lcs)
題目描述:給你兩個陣列,可以是數字的,也可以是字串,我們假設是數字的!舉個例子:
x = 1, 5, 6, 4, 1, 3, 7
y = 1, 1, 6, 8, 3, 4, 7
求乙個新的陣列s,該陣列中的每個數均是x和y陣列中的公共數,並滿足原陣列中數字的前後關係,這樣的陣列有很多個,比如說 (1,1),(1,1,3,7),(1,6,7)等。同時s陣列要是長度最長的那個,像上面的(1,1,3,7),長度是4,那麼即為所求解!
做dp題目最重要的一點是能正確的構造出dp函式,如果能很好的構造出來,就成功一半了。
dp[i][j] 表示x陣列的前i位和y陣列的前j位之前的lcs,那麼它可以由前面三個狀態推出來。
0 if(i=0 || j=0) --初始化,不難理解,不管是x還是y陣列,只要有乙個長度是0,那麼s陣列就是0
dp[i][j] = max(dp[i-1][j],dp[i][j-1] if(i,j>0 && x[i] != y[j]) --s陣列沒有新增數字,那麼只能從前面繼承來,乙個從x,乙個從y,看那個大
dp[i-1][j-1] + 1 if(i,j>0 && x[i] == y[j]) --如果是兩個相同,當然是把s陣列加1,可以看成x和y都繼承了
**很簡單,兩個for迴圈就可以了。
這樣我們可以總結出該問題的遞迴形式表達:
按照動態規劃的思想,對問題的求解,其實就是對子問題自底向上的計算過程。這裡,計算c[i][j]時,c[i-1][j-1]、c[i-1][j]、c[i][j-1]已經計算出來了,這樣,我們可以根據x[i]與y[j]的取值,按照上面的遞推,求出c[i][j],同時把路徑記錄在b[i][j]中(路徑只有3中方向:左上、左、上,如下圖)。
計算c矩陣的時間複雜度是o(m*n);根據b矩陣尋找最長公共子串行的過程,由於每次呼叫至少向上或向左移動一步,這樣最多需要(m+n)次就會i = 0或j = 0,也就是演算法時間複雜度為o(m+n)。
#include #include #include #include using namespace std;
void lcs_print(int **lcs_direction, char *str, int row, int column)
else if(lcs_direction[row][column] == 2)
else if(lcs_direction[row][column] == 3)
}int lcs(char *str1, char *str2)
for(int i = 0; i < nlen1; i++)
lcs_length[i][0] = 0;
for(int i = 0; i < nlen2; i++)
lcs_length[0][i] = 0;
for(int i = 0; i < nlen1; i++)
}cout<
else}}
lcs_print(lcs_direction, str1, nlen1 - 1, nlen2 - 1);
cout<
最長公共子串行 最長公共子串
1 最長公共子串行 採用動態規劃的思想,用乙個陣列dp i j 記錄a字串中i 1位置到b字串中j 1位置的最長公共子串行,若a i 1 b j 1 那麼dp i j dp i 1 j 1 1,若不相同,那麼dp i j 就是dp i 1 j 和dp i j 1 中的較大者。class lcs el...
最長公共子串行 最長公共子串
1.區別 找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。2 最長公共子串 其實這是乙個序貫決策問題,可以用動態規劃來求解。我們採用乙個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧 bab 和 caba 當然我們現在一眼就可以看出來最長公...
最長公共子串 最長公共子串行
子串要求連續 子串行不要求連續 之前的做法是dp求子序列 include include include using namespace std const int inf 0x3f3f3f3f const int mod 1000000007 string s1,s2 int dp 1010 10...