#include <stdio.h> /** * 原題: * 給定兩個字符串S和T,求出這兩個字符串的最長公共子序列的長度 * 例如X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A} * 則它們的lcs是4 ({B,C,B,A}和{B,D,A,B})。求出一個即可。 */ #define MAX(x,y) (x>y?x:y) #define SL 7 #define TL 6 static char s[SL+2] = " ABCBDAB"; static char t[TL+2] = " BDCABAB"; /** * 思路: * 設置子問題:求s的前i個字符組成的字符串與t的前j個字符組成的字符串的最大公共子序列長度 * 找出邊界:顯然i或j等於0時,最大公共子序列長度爲0 */ //解法1:遞歸 int solve_1(int i, int j){ if (i == 0 || j == 0) return 0; if (s[i] == t[j]) return MAX(solve_1(i-1, j-1) + 1, MAX(solve_1(i-1, j), solve_1(i, j-1))); return MAX(solve_1(i-1, j), solve_1(i, j-1)); } //解法2:遞歸+記憶數組 static int memo[SL+1][TL+1]; int solve_2(int i, int j){ if (i == 0 || j == 0) return memo[i][j] = 0; if (memo[i][j] > -1) return memo[i][j]; if (s[i] == t[j]) return memo[i][j] = MAX(solve_2(i-1, j-1) + 1, MAX(solve_2(i-1, j), solve_2(i, j-1))); return memo[i][j] = MAX(solve_2(i-1, j), solve_2(i, j-1)); } //解法3:遞推 static int maxLen[SL+1][TL+1]; int solve_3(){ for (int i = 1; i <= SL; ++i) { for (int j = 1; j <= TL; ++j) { if (s[i] == t[j]) maxLen[i][j] = MAX(maxLen[i-1][j-1] + 1, MAX(maxLen[i-1][j], maxLen[i][j-1])); else maxLen[i][j] = MAX(maxLen[i-1][j], maxLen[i][j-1]); } } return maxLen[SL][TL]; } int main() { printf("solve_1:%d\n", solve_1(SL, TL)); for (int i = 0; i <= SL; ++i) { for (int j = 0; j <= TL ; ++j) { memo[i][j] = -1; } } printf("solve_2:%d\n", solve_2(SL, TL)); // for (int i = 0; i <= SL; ++i) { // for (int j = 0; j <= TL ; ++j) { // printf("%d\t", memo[i][j]); // } // printf("\n"); // } printf("solve_3:%d\n", solve_3()); // for (int i = 0; i <= SL; ++i) { // for (int j = 0; j <= TL ; ++j) { // printf("%d\t", maxLen[i][j]); // } // printf("\n"); // } return 0; }
運行結果:
solve_1:4
solve_2:4
solve_3:4