跟著程式設計之美學演算法 最長公共子串行

2022-07-26 10:12:09 字數 3506 閱讀 4899

最長公共子串行是乙個很經典的動態規劃問題,最近正在學習動態規劃,所以拿來這裡再整理一下。

這個問題在《演算法導論》中作為講動態規劃演算法的例題出現。

動態規劃,眾所周知,第一步就是找子問題,也就是把乙個大的問題分解成子問題。這裡我們設兩個字串a、b,a = "a0, a1, a2, ..., am-1",b = "b0, b1, b2, ..., bn-1"。

(1)如果am-1 == bn-1,則當前最長公共子串行為"a0, a1, ..., am-2"與"b0, b1, ..., bn-2"的最長公共子串行與am-1的和。長度為"a0, a1, ..., am-2"與"b0, b1, ..., bn-2"的最長公共子串行的長度+1。

(2)如果am-1 != bn-1,則最長公共子串行為max("a0, a1, ..., am-2"與"b0, b1, ..., bn-1"的公共子串行,"a0, a1, ..., am-1"與"b0, b1, ..., bn-2"的公共子串行)

如果上述描述用數學公式表示,則引入乙個二維陣列c,其中c[i][j]記錄x[i]與y[j]的lcs長度,b[i][j]記錄c[i][j]是通過哪乙個子問題的值求得的,即,搜尋方向。

這樣我們可以總結出該問題的遞迴形式表達:

按照動態規劃的思想,對問題的求解,其實就是對子問題自底向上的計算過程。這裡,計算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)。

一下是**實現 

1 #include 2 #include 3 #include 

4 #include

56using

namespace

std; 7

8void lcs_print(int **lcs_direction, char *str, int row, int

column) 9

24else

if(lcs_direction[row][column] == 2)

25 29else

if(lcs_direction[row][column] == 3)

30 34}

3536int lcs(char *str1, char *str2) 37

5657for(int i = 0; i < nlen1; i++)

58 lcs_length[i][0] = 0;

59for(int i = 0; i < nlen2; i++)

60 lcs_length[0][i] = 0;

6162

for(int i = 0; i < nlen1; i++) 63

68}

6970 cout<

init ok!

"<

72for(int i = 0; i ) 73

83else

84 lcs_length[i][j] = 0;

85} 86

else

if(str1[i] ==str2[j]) 87

91else

if(lcs_length[i - 1][j] > lcs_length[i][j - 1])

92 96else

97101

}102

}103

104 lcs_print(lcs_direction, str1, nlen1 - 1, nlen2 - 1

);105 cout<

106int nlcs = lcs_length[nlen1 - 1][nlen2 - 1

];107

for(int i = 0; i < nlen1; i++)

108112

delete lcs_length;

113delete lcs_direction;

114return

nlcs;

115}

116117

intmain()

118複製**

1 #include 2 #include 3 #include 

4 #include 56

using

namespace

std;78

void lcs_print(int **lcs_direction, char *str, int row, int

column)924

else

if(lcs_direction[row][column] == 2)25

29else

if(lcs_direction[row][column] == 3)30

34}3536

int lcs(char *str1, char *str2)

3756

57for(int i = 0; i < nlen1; i++)

58 lcs_length[i][0] = 0;59

for(int i = 0; i < nlen2; i++)

60 lcs_length[0][i] = 0;61

62for(int i = 0; i < nlen1; i++)

6368}69

70 cout<

init ok!

"<

7172

for(int i = 0; i )

7383

else

84 lcs_length[i][j] = 0;85

}86else

if(str1[i] ==str2[j])

8791

else

if(lcs_length[i - 1][j] > lcs_length[i][j - 1

])92

96else

97101

}102

}103

104 lcs_print(lcs_direction, str1, nlen1 - 1, nlen2 - 1

);105 cout<

106int nlcs = lcs_length[nlen1 - 1][nlen2 - 1

];107

for(int i = 0; i < nlen1; i++)

108112

delete lcs_length;

113delete lcs_direction;

114return

nlcs;

115}

116117

intmain()

118

跟著程式設計之美學演算法 最長公共子串行

最長公共子串行是乙個很經典的動態規劃問題,最近正在學習動態規劃,所以拿來這裡再整理一下。這個問題在 演算法導論 中作為講動態規劃演算法的例題出現。動態規劃,眾所周知,第一步就是找子問題,也就是把乙個大的問題分解成子問題。這裡我們設兩個字串a b,a a0,a1,a2,am 1 b b0,b1,b2,...

程式設計之美 最長公共子串行 子串

求最長公共子串有兩種情況 1,要求子串連續 2,不要求子串連續 1.要求子串連續這種情況比較簡單 原理如下 設定乙個矩陣p,p i j 表示以str1 i 和str2 j 結尾的子串的最大公共子串的長度。利用如下遞推式求解 如果 str1 i str2 j p i j 0.如果 str1 i str...

最長公共子串行 最長公共子串

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...