Skip to content

Commit 40ff0ea

Browse files
committed
feat: Translate the Longest Common Subsequence...
...problem.
1 parent e180040 commit 40ff0ea

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Subsecuencia común más larga
2+
3+
#### Declaración de problema
4+
5+
Dadas dos cadenas `S` y `T`, busque la longitud de la subsecuencia común más larga (<b>LCS</b>).
6+
7+
#### Enfoque
8+
9+
Que el `dp[i][j]` sea la longitud de la subsecuencia común más larga de los prefijos `S[1..i]` y `T[1..j]`. Nuestra respuesta (la longitud de LCS) es `dp[| S|] [| T|]`, ya que el prefijo de la longitud de la cadena es la propia cadena.
10+
11+
Tanto `dp[0][i]` como `dp[i][0]` son `0` para cualquier `i`, desde el LCS de prefijo vacío y cualquier otra cosa es una cadena vacía.
12+
13+
Ahora, vamos a tratar de calcular `dp[i][j]` para cualquier `i`, `j`. Digamos `S[1..i] = *A` y `T[1..j] = *B` donde `*` significa cualquier secuencia de letras (podría ser diferente para `S` y `T`), `A` significa cualquier letra y `B` significa cualquier letra diferente de `A`. Dado que `A != B`, nuestro LCS no incluye `A` o `B` como último carácter. Así que podríamos tratar de tirar a la distancia el personaje `A` o `B`. Si lanzamos `A`, nuestra longitud LCS será `dp[i - 1][j]` (ya que tenemos prefijos `S[1..i - 1]` y `T[1..j]`). Si intentamos lanzar el carácter `B`, tendremos prefijos `S[1..i]` y `T[1..j - 1]`, por lo que la longitud de LCS será `dp[i][j - 1]`. Mientras buscamos la subsecuencia común más <b>larga<b>, elegiremos <b>el valor máximo</b> de `dp[i][j - 1]` y `dp[i - 1] [j]`.
14+
15+
¿Pero qué pasa si `S[1..i] = *A` y `T[1..j] = *A`? Podríamos decir que el LCS de nuestros prefijos es LCS de prefijos `S[1..i - 1]` y `T[1..j - 1]` <b>más</b> la letra `A`. Así que `dp[i][j] = dp[i - 1][j - 1] + 1` es igual a `S[i] = T[j]`.
16+
17+
Pudimos ver que podemos llenar nuestra tabla `dp` fila por fila, columna por columna. Así que nuestro algoritmo será como:
18+
19+
- Digamos que tenemos cuerdas `S` de la longitud N y `T` de la longitud M (numeradas a partir de 1). Vamos a crear la tabla `dp` de tamaño `(N + 1) x (M + 1)` numerada a partir de 0.
20+
- Vamos a llenar la 0ª fila y la 0ª columna de `dp` con 0.
21+
- A continuación, seguimos el algoritmo:
22+
23+
```python
24+
for i in range(1..N):
25+
for j in range(1..M):
26+
if(S[i] == T[j])
27+
dp[i][j] = dp[i - 1][j - 1] + 1
28+
else
29+
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
30+
```
31+
32+
#### Complejidad horaria
33+
34+
`O(N * M)` - En cualquier caso
35+
36+
#### Complejidad espacial
37+
38+
`O(N * M)` - implementación simple
39+
`O(min {N, M})` - implementación de dos capas (como `dp[i][j]` depende sólo de las capas i-th e i-th, coudld almacenamos sólo dos capas).
40+
41+
#### Ejemplo
42+
43+
Digamos que tenemos cuerdas `ABCB` y `BBCB`. Construiremos una mesa de este tipo:
44+
45+
```
46+
# # Una B C B
47+
# 0 0 0 0 0
48+
B 0 ? ? ? ?
49+
B 0 ? ? ? ?
50+
C 0 ? ? ?
51+
B 0 ? ? ? ?
52+
```
53+
54+
Ahora empezaremos a llenar nuestra mesa desde la 1ª fila. Puesto que `S[1] = A` y `T[1] = B`, `dp[1] [1]` será el valor máximo de `dp[0] [1] = 0` y `dp[1] [0] = 0`. Así que `dp[1] [1] = 0`. Pero ahora `S[2] = B = T[1]`, así que `dp[1] [2] = dp[0] [1] + 1 = 1`. `dp[1] [3]` es `1` desde `A != C` y elegimos `max{dp[1] [2], dp[0] [3]}`. Y `dp[1] [4] = dp[0] [3] + 1 = 1`.
55+
56+
```
57+
# # A B C B
58+
# 0 0 0 0 0
59+
B 0 0 1 1 1
60+
B 0 ? ? ? ?
61+
C 0 ? ? ? ?
62+
B 0 ? ? ? ?
63+
```
64+
65+
Ahora vamos a llenar la otra parte de la tabla:
66+
67+
```
68+
# # A B C B
69+
# 0 0 0 0 0
70+
B 0 0 1 1 1
71+
B 0 0 1 1 2
72+
C 0 0 1 2 2
73+
B 0 0 1 2 3
74+
```
75+
76+
Así que la longitud de LCS es `dp[4] [4] = 3`.
77+
78+
#### Enlaces de implementación de código
79+
80+
- [Java](https://github.com/TheAlgorithms/Java/blob/master/Dynamic%20Programming/LongestCommonSubsequence.java)
81+
- [Python](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/longest_common_subsequence.py)
82+
- [C++](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/Dynamic%20Programming/Longest%20Common%20Subsequence.cpp)
83+
- [JavaScript](https://github.com/TheAlgorithms/Javascript/blob/master/Dynamic-Programming/LongestCommonSubsequence.js)
84+
- [Go](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longestCommonSubsequence.go)
85+
- [Rust](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/longest_common_subsequence.rs)
86+
87+
#### Explicación en YouTube
88+
89+
[Explicación en YouTube de Tushar Roy](https://youtu.be/NnD96abizww)

0 commit comments

Comments
 (0)