Skip to Content

LCS on Permutations

Solución lenta

Complejidad temporal: O(N2)\mathcal O(N^2)

Ver aquí.

Solución eficiente

En la solución O(N2)\mathcal O(N^2), incrementamos el arreglo de DP solo si a[i]=b[j]a[i] = b[j], pero como ambos arreglos son permutaciones de longitud NN, para cada a[i]a[i] debe haber solo un elemento coincidente en bb.

Creemos un arreglo pospos donde pos[x]pos[x] es el índice de xx en aa (a[pos[x]]=xa[pos[x]] = x). Luego, podemos crear otro arreglo, cc, donde c[i]c[i] guarda pos[b[i]]pos[b[i]].

Nótese que cada subsecuencia creciente x1kx_{1 \dots k} en cc corresponde a una subsecuencia común entre aa y bb. La subsecuencia creciente c[x1],c[x2],c[xk]c[x_1], c[x_2], \dots c[x_k] corresponde a la subsecuencia común b[x1],b[x2],b[xk]b[x_1], b[x_2], \dots b[x_k], que es equivalente a a[c[x1]],a[c[x2]],a[c[xk]]a[c[x_1]], a[c[x_2]], \dots a[c[x_k]]. Así, la longitud de la subsecuencia común más larga entre aa y bb es la subsecuencia creciente más larga de cc.

Implementación

Complejidad temporal: O(NlogN)\mathcal O(N\log N)

#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n, a[N], b[N], c[N], pos[N]; vector<int> lis; int main() { cin.tie(0)->sync_with_stdio(0); cin >> n; for (int i = 1; i <= n; ++i) { cin >> a[i]; // pos is the inverse of a pos[a[i]] = i; } for (int i = 1; i <= n; ++i) { cin >> b[i]; } for (int i = 1; i <= n; ++i) { c[i] = pos[b[i]]; } for (int i = 1; i <= n; ++i) { int p = lower_bound(begin(lis), end(lis), c[i]) - begin(lis); if (p == lis.size()) lis.push_back(c[i]); else lis[p] = c[i]; } cout << lis.size() << '\n'; }
import java.io.*; import java.util.*; public class Main { // CodeSnip{Kattio} public static void main(String[] args) { Kattio io = new Kattio(); int n = io.nextInt(); int[] a = new int[n + 1], b = new int[n + 1], c = new int[n + 1], LIS = new int[n + 1]; int[] position = new int[n + 2]; for (int i = 1; i <= n; i++) { a[i] = io.nextInt(); // position is the inverse of a position[a[i]] = i; } for (int i = 1; i <= n; i++) { b[i] = io.nextInt(); } for (int i = 1; i <= n; i++) { c[i] = position[b[i]]; } // Length of the LIS int len = 0; for (int i = 1; i <= n; i++) { // We find the value which is >= the target value using // Arrays.binarySearch. int val = Arrays.binarySearch(LIS, 0, len, c[i]); if (val < 0) val = Math.abs(val + 1); LIS[val] = c[i]; if (val == len) len++; } io.println(len); io.close(); } }
from bisect import bisect_left n = int(input()) a = list(map(int, input().split())) b = list(map(int, input().split())) # pos is the inverse of a pos = [0] * (n + 1) c = [0] * n for i in range(n): pos[a[i]] = i + 1 for i in range(n): c[i] = pos[b[i]] lis = [] for i in range(n): p = bisect_left(lis, c[i]) if p == len(lis): lis.append(c[i]) else: lis[p] = c[i] print(len(lis))