最長共同子序列 (Longest Common Subsequence; LCS) - Part 1

1.1 - Longest Common Subsequence (LCS)


1.2 - LCS: Dynamic Programming

1.2.1 - 分割問題 (Partition)

1.2.2 - 計算 Longest Common Subsequence (LCS) 的長度

int s1[7] = {2, 5, 7, 9, 3, 1, 2};
int s2[5] = {3, 5, 3, 2, 8};
int length[8][6];

void findLCS() {
    // 初始化:當 s1 或 s2 為空集合,則 LCS 為空集合。
    for (int i = 0; i <= 7; ++i)
        length[i][0] = 0;
    for (int j = 0; j <= 5; ++j)
        length[0][j] = 0;

    // 依照遞迴公式填表格
    for (int i = 1; i <= 7; ++i) {
        for (int j = 1; j <= 7; ++j) {
            if (s1[i - 1] == s2[j - 1])
                // 因為 e1 的長度為 1,故要 +1
                length[i][j] = length[i - 1][j - 1] + 1;
            else
                length[i][j] = max(length[i - 1][j], length[i][j - 1]);
        }
    }

    // Print the result
    printf("LCS length: %d\n", length[7][5]);
}

1.2.3 - 找出一個 Longest Common Subsequence (LCS)

int s1[7] = {2, 5, 7, 9, 3, 1, 2};
int s2[5] = {3, 5, 3, 2, 8};
int length[8][6];
int LCS[8][6];  // 記錄每一格的的結果是從哪一格而來
int seq[5]

void findLCS() {
    // Initialize
    for (int i = 0; i <= 7; ++i)
        length[i][0] = 0;
    for (int j = 0; j <= 5; ++j)
        length[0][j] = 0;
    
    // Start
    for (int i = 1; i <= 7; ++i) {
        for (int j = 1; j <= 7; ++j) {
            if (s1[i - 1] == s2[j - 1]) {
                length[i][j] = length[i - 1][j - 1] + 1;
                // LCS from the left-top
                LCS[i][j] = 0
            }
            else {
                length[i][j] = max(length[i - 1][j], length[i][j - 1]);
                if (length[i - 1][j] < length[i][j - 1]) {
                    length[i][j] = length[i][j - 1];
                    // LCS from the left
                    LCS[i][j] = 1;
                }
                else {
                    length[i][j] = length[i - 1][j];
                    // LCS from the top
                    LCS[i][j] = 2;
                }
            }
        }
    }

    // Print the result
    printf("LCS length: %d\n", length[7][5]);
    printf("LCS (Loop): ");
    printLCS_loop(7, 5);
    printf("LCS (Recursive): ");
    printLCS_recursive(7, 5);
}

/* Loop version */
void printLCS_loop(int i, int j) {
    int len = length[i][j];

    while (len > 0) {
        if (LCS[i][j] == 0) {
            --len;
            seq[len] = s1[i];
        }
        else if (LCS[i][j] == 1)
            --j
        else
            --i;
    }

    len = length[i][j];
    for (int l = 0; l < len; ++l)
        printf("%d ", seq[l]);
}

/* Recursive version */
void printLCS_recursive(int i, int j) {
    // End of null set
    if (i == 0 || j == 0)
        return;
    
    if (LCS[i][j] == 0) {
        printLCS_recursive(i - 1, j - 1);
        printf("%d ", s1[i]);
    }
    else if (LCS[i][j] == 1)
        printLCS_recursive(i, j - 1);
    else
        printLCS_recursive(i - 1, j);
}

1.2.4 - 如何「找出所有的 LCS」?

1.2.5 - 節省記憶體空間


Practice


References

profile-image
David Lu
Hello, I'm David Lu. I am a graduate student in Department of Computer Science at National Chiao Tung University, Taiwan. I am in the Networking and Sensing Systems (NSS) Lab at NCTU. If you have any question, please feel free to contact with me.
comments powered by Disqus