最长公共子序列是一个经典的基础算法问题 在两个序列中 如果序列1中的元素a也存在于序列2,则认为a是1,2的公共元素。 当序列3中的每一个元素都能够满足在不改变次序的情况下依次属于1,2,那么则认为3是1,2的公共子序列。多个公共子序列中,元素最多的即为最长公共子序列。

在学堂在线的算法课程中,有比较详细的课程讲述这个算法的构思。但是没有给出具体的实现,这里来自己实现一下。

首先使用表格模拟排列组合的所有情况: 以{a,b,c,d,e},{a,b,q,c,b}为例:

A\B a b q c b
a 1 1 1 1 1
b 1 2 2 2 2
c 1 2 2 3 3
d 1 2 2 3 3
e 1 2 2 3 3

实际上看到这样的填充,直觉上就应该反应出来,使用二维数组来解决。 其中当 A[i]!=B[j]时,取左方或者上方更大的,而A[i]==B[j]的时候,取T[i-1][j-1] + 1。这里i=0或j=0的时候就不方便了,所以给矩阵默认增加一行 0 行。即

A\B 0 a b q c b
0 0 0 0 0 0 0
a 0 1 1 1 1 1
b 0 1 2 2 2 2
c 0 1 2 2 3 3
d 0 1 2 2 3 3
e 0 1 2 2 3 3

这样的话,无论如何都可以取到左侧和上方的值。而对应的集合数量、i、j分别+1.

#include <iostream>

using namespace std;

inline int larger( int a, int b ){

    return a>b ? a : b;
}

template <typename T>
int subSquence( T* const A, T* const B, int sizeA, int sizeB ){

    sizeA++;sizeB++; // 增加默认0行
    int t[sizeA][sizeB];
    for( int i=0; i<sizeA; i++ ){
        for( int j=0; j<sizeB; j++ ){
            if( i == 0 || j == 0 ){ // 0行 || 0列
                t[i][j] = 0;
            }else if( A[i-1] == B[j-1] ){ // 相等 * size已经+1了
                t[i][j] = t[i-1][j-1] + 1;
            }else{
                t[i][j] = larger( t[i-1][j], t[i][j-1] );
            }
        }
    }
    return t[sizeA-1][sizeB-1];
}



int main(){

    int a[3] = {1,2,5};
    int b[4] = {2,3,4,5};

    cout << subSquence( a , b, 3, 4 ) << endl;
    return 0;
}

文章地址:




标签: 算法, algorithm, 数据结构、算法与应用, 最长公共子序列

添加新评论