算法二十一:最长公共子序列

问题描述

给定两个 1 到 n 的排列 A,B (即长度为 n 的序列,其中 [1,n] 之间的所有数都出现了恰好一次)。

求它们的最长公共子序列长度。

输入格式

第一行一个整数 n ,意义见题目描述。

第二行 n 个用空格隔开的正整数 A[1],…,A[n],描述排列 A。

第三行 n 个用空格隔开的正整数 B[1],…,B[n],描述排列 B。

输出格式

一行一个整数,表示 A,B 的最长公共子序列的长度。

样例输入

5
1 2 4 3 5
5 2 3 4 1

样例输出

2

样例解释

(2,3) 和 (2,4) 都可以是这两个序列的最长公共子序列。

提示

[把 A 中的所有数替换成其在 B 中出现的位置,想一想,新序列的最长上升子序列和所求的东西有什么关系呢?]

一. 伪代码

二. 具体实现

#include <bits/stdc++.h>
using namespace std;
// ================= 代码实现开始 =================
const int inf = 1e9;
//pos:b中各元素出现位置
//f:f[i]表示长度为i的最长公共子序列的末尾最小可能元素

vector<int> pos,f;
// 计算最长公共子序列的长度
// n:表示两序列长度
// a:描述序列 a(这里需要注意的是,由于 a 的下标从 1 开始,因此 a[0] 的值为-1,你可以忽略它的值,只需知道我们从下标 1 开始存放有效信息即可)
// b:描述序列b(同样地,b[0] 的值为 -1)
// 返回值:最长公共子序列的长度

int LCS(int n, vector<int> a, vector<int> b) {
    //初始化,调整pos,f数组的长度,并将f数组置初值
    pos.resize(n+1);
    f.resize(n+2,inf);
    for(int i=1; i<=n; ++i)
        pos[b[i]] = i; //记录b序列中各元素出现位置
    for(int i=1; i<=n; ++i)
        a[i] = pos[a[i]]; //如何处理序列a呢
    f[0] = 0;
    for(int i=1; i<=n; ++i)
        *lower_bound(f.begin(),f.end(),a[i]) = a[i];
    return int(lower_bound(f.begin(),f.end(),n+1) - f.begin()) -1;
}
// ================= 代码实现结束 =================


猜你喜欢

转载自blog.csdn.net/wydyd110/article/details/80898685