【模型】LCS

LCS

LCS就是给定2个序列(广义来说是n个,在这里我们只讨论两个序列的情形),找出其中最长的公共子序列。
于LIS相似,LCS也有两种做法,一种是 O(n2) O ( n 2 ) ,一种是 O(nlog2n) O ( n l o g 2 n )

§ § LCS O(n2) O ( n 2 )

也是朴素的DP,状态转移方程:
fi,j={fi1,j1+1maxfi1,j,fi,j1ai==ajai<>aj f i , j = { f i − 1 , j − 1 + 1 a i == a j m a x f i − 1 , j , f i , j − 1 a i <> a j

Code: C o d e :

int LCS(int n, std::vector< int > &a, int m, std::vector< int > &b) {
    std::vector< std::vector< int > > f(n + 1, std::vector< int >(m + 1));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1;
            else f[i][j] = std::max(f[i - 1][j], f[i][j - 1]);
    return f[n][m];
}

§ § LCS O(nlog2n) O ( n l o g 2 n )

这种做法是将LCS模型转化为了LIS,再运用LIS的 O(nlog2n) O ( n l o g 2 n ) 算法进行求解,那么如何将LCS转化成LIS呢,首先遍历其中的一个序列,建立一个索引,再遍历另外一个数组,利用索引弄出另外一个数组,对另外一个数组进行LIS求解得到结果
下面给出一个表格(vector的0由于没有用,被省略)

vector 1 2 3 4 5 6 7 8 9
a(seq1) 1 7 6 3 4 5 8
b(seq2) 6 9 7 3 4 3 5
index(索引) 1 0 4 5 6 3 2 7 0
c(seq) 3 2 4 5 4 6

只看a和b很容易得出LCS(a, b) = 4,而C的LIS也是4.
这个索引是怎么得出的呢?
我们根据a进行索引
index[1]表示1在a中出现的位置是1.
index[2]表示2在a中出现的位置是7
以此类推。
然后我们又根据index和b得出c,c的得出规则如下:
b[1]在a中出现过,索引为3,所以c[1]=3
b[2]在a中没有出现,跳过(b[2]不可能是LCS中的元素)
b[3]在a中出现过,索引为2,所以c[2]=2
以此类推,c数组就的出来了。
然后,对C做一次LIS,就得出结果,证明算法正确性很简单,这里也就不再赘述。

Code: C o d e :

int LCS(std::vector< int > &a, std::vector< int > &b) {
    static const int MAXN = 1000000 + 10;
    std::vector< int > c(1), index(MAXN);
    for (unsigned int i = 1; i < b.size(); i++) index[b[i]] = i;
    for (unsigned int i = 1; i < a.size(); i++) 
        if (index[a[i]]) c.push_back(index[a[i]]);
    return LIS(c);                      
}

你可能感兴趣的:(DP,LCS)