简介
LCS
算法
首先我们看一下最简单且使用的 $O(n^2)$ 做法
我们令 f[i][j]
表示第一个序列匹配到第i
个,第二个序列匹配到第j
个时的最长公共子序列的长度
转移直接继承或者是i
和j
匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <cstdio> #define maxn 1010 using namespace std;
int n, a[maxn], b[maxn];
int f[maxn][maxn];
int main() { cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; for (int i = 1; i <= n; ++i) cin >> b[i]; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { f[i][j] = max(f[i - 1][j], f[i][j - 1]); if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1; } cout << f[n][n] << endl; return 0; }
|
另外我们考虑如何处理序列中没有相同元素的特殊情况,能否将时间复杂度优化到 $O(n^2)$ 以下
我们考虑在原方法当且仅当a[i]==b[j]
时才会增加f
的值
所以我们考虑在这方面进行优化
我们对第二个数组做一个类似hash
的东西
我们将每个数变成在第一个数组中出现该数的下标
那么问题被转换成了LIS
问题
时间复杂度 $O(nlogn)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <cstdio> #include <algorithm> #define maxn 100010 using namespace std;
int n, a[maxn], b[maxn], p[maxn];
int d[maxn], len;
int main() { cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i], p[a[i]] = i; for (int i = 1; i <= n; ++i) cin >> b[i], b[i] = p[b[i]]; for (int i = 1; i <= n; ++i) { if (b[i] > d[len]) d[++len] = b[i]; else *lower_bound(d + 1, d + len + 1, b[i]) = b[i]; } cout << len << endl; return 0; }
|