Longest Increasing Subsequence (LIS) encuentra la subsecuencia más larga donde cada elemento es estrictamente mayor que el anterior. Es un problema DP clásico con una solución óptima O(n log n) usando patience sorting.
La versión DP naïve es O(n²), pero existe un método más rápido que combina DP con búsqueda binaria sobre pilas de valores.
Cómo Funciona
DP O(n²)
dp[i] = longitud LIS terminando en índice i.
dp[i] = 1 + max(dp[j] for j < i if A[j] < A[i])
Patience Sorting O(n log n)
Mantén un array tails donde tails[k] es el menor tail posible de una subsecuencia creciente de longitud k+1.
Para cada x en el array:
- Busca el primer
tails[i] >= x - Reemplaza
tails[i] = x - Si
xes mayor que todos, añade atails
Idea Clave
Patience sorting es la intuición: imagina barajar cartas y colocarlas en pilas donde cada pila tiene un top card mayor que las siguientes. El número de pilas al final es la longitud LIS. Mantener el menor tail posible en cada pila permite búsqueda binaria.
La propiedad clave: tails siempre está ordenado, por lo que lower_bound funciona en O(log n) por elemento.
Ejemplo Trabajado
A = [10, 9, 2, 5, 3, 7, 101, 18]
Proceso patience sorting:
10→ tails =[10]9→ reemplaza10→ tails =[9]2→ reemplaza9→ tails =[2]5→ añade → tails =[2, 5]3→ reemplaza5→ tails =[2, 3]7→ añade → tails =[2, 3, 7]101→ añade → tails =[2, 3, 7, 101]18→ reemplaza101→ tails =[2, 3, 7, 18]
Resultado: longitud LIS = 4 ([2, 3, 7, 18] o [2, 3, 7, 101]).
Casos Extremos y Trampas
- Estrictamente creciente —
A[i-1] < A[i], no<=. Usalower_bound. - No estrictamente creciente — usa
upper_boundpara permitir empates. - Reconstrucción — mantén
prev[i]ytails_idxpara reconstruir la secuencia. - Permutación — en toda permutación de
[1..n], LIS × LDS ≥ n (Erdős–Szekeres).
Comparación
| Método | Complejidad | Espacio | Notas |
|---|---|---|---|
| DP O(n²) | O(n²) | O(n) | Simple, reconstruct fácil |
| Patience sorting | O(n log n) | O(n) | Más rápido, reconstruct requiere cuidado |
Aplicaciones
- Series temporales — detectar tendencias crecientes
- Bioinformática — alineamiento de secuencias
- Procesamiento de texto — diff, spell checkers
- Enseñanza — introduce patience sorting y binary search en DP
Trayectoria de Práctica
- Implementa DP O(n²); traza el ejemplo con tablas
dpyprev. - Implementa patience sorting O(n log n); usa
bisect_lefto binary search manual. - Añade reconstrucción: mantén
tails_idxpara mapeartailsa índices originales. - ¿Por qué
tailssiempre está ordenado? Prueba con un contraejemplo. - Investiga Erdős–Szekeres: ¿cuántas secuencias crecientes/decrecientes garantiza una permutación?