diff --git a/longest-common-subsequence/longest-common-subsequence-tutorial.pdf b/longest-common-subsequence/longest-common-subsequence-tutorial.pdf index 19af11e..cd6ae76 100644 Binary files a/longest-common-subsequence/longest-common-subsequence-tutorial.pdf and b/longest-common-subsequence/longest-common-subsequence-tutorial.pdf differ diff --git a/longest-common-subsequence/longest-common-subsequence-tutorial.tex b/longest-common-subsequence/longest-common-subsequence-tutorial.tex index b037364..c07af40 100644 --- a/longest-common-subsequence/longest-common-subsequence-tutorial.tex +++ b/longest-common-subsequence/longest-common-subsequence-tutorial.tex @@ -64,4 +64,49 @@ dp[0][j] = 0 \quad \forall j \ge 0 dp[i][0] = 0 \quad \forall i \ge 0 \] -Isto representa que, se uma das strings tiver tamanho zero, nenhuma subsequência comum pode ser formada.\end{document} +Isto representa que, se uma das strings tiver tamanho zero, nenhuma subsequência comum pode ser formada. + +\subsection{Recuperação da Subsequência Comum} + +Após o preenchimento da matriz \( dp \), o valor \( dp[n][m] \) fornece o comprimento da maior subsequência comum entre \( s_1 \) e \( s_2 \). +No entanto, para obter também a subsequência em si, é necessário realizar um processo de \textit{backtracking} sobre a matriz. + +A ideia consiste em iniciar a partir da posição \( (n, m) \) da matriz e caminhar em direção à origem. +Em cada passo: + +\begin{itemize} + \item Se \( s_1[i] = s_2[j] \), então este caractere faz parte da LCS. Nesse caso, retrocedemos para \( (i-1, j-1) \). + \item Caso contrário, avançamos para o vizinho que contém o maior valor entre \( dp[i-1][j] \) e \( dp[i][j-1] \), pois esse vizinho indica o caminho que manteve o comprimento máximo da subsequência. +\end{itemize} + +Como a subsequência é reconstruída de trás para frente, os caracteres encontrados devem ser adicionados no início da string resultante. + +O algoritmo para recuperar uma subsequência comum de comprimento máximo é o seguinte: + +\begin{verbatim} +int i = n; // ponteiro para s1 +int j = m; // ponteiro para s2 +string lcs = ""; // subsequência comum sendo reconstruída + +// Enquanto ainda houver caracteres a considerar +while (i > 0 && j > 0) { + + // Caso 1: os caracteres são iguais → fazem parte da LCS + if (s1[i - 1] == s2[j - 1]) { + lcs = s1[i - 1] + lcs; // adiciona no início da string + i--; + j--; + } + // Caso 2: se o valor de cima é maior, movemos para cima + else if (dp[i - 1][j] > dp[i][j - 1]) { + i--; + } + // Caso 3: caso contrário, movemos para a esquerda + else { + j--; + } +} + +\end{verbatim} + +Ao final desse processo, a string \texttt{lcs} conterá uma maior subsequência comum entre as duas strings.\end{document} diff --git a/longest-common-subsequence/longest-common-subsequence.pdf b/longest-common-subsequence/longest-common-subsequence.pdf index c4e8ea7..2b81977 100644 Binary files a/longest-common-subsequence/longest-common-subsequence.pdf and b/longest-common-subsequence/longest-common-subsequence.pdf differ diff --git a/longest-common-subsequence/longest-common-subsequence.tex b/longest-common-subsequence/longest-common-subsequence.tex index 1961b4c..027fe00 100644 --- a/longest-common-subsequence/longest-common-subsequence.tex +++ b/longest-common-subsequence/longest-common-subsequence.tex @@ -3,18 +3,21 @@ \begin{document} \begin{ProblemaAutor}{}{Maior Subsequência Comum}{1}{256}{} -O problema consiste em determinar o comprimento da maior subsequência comum entre duas strings. -Uma subsequência é uma sequência que pode ser obtida a partir da string original removendo-se zero ou mais caracteres, sem alterar a ordem relativa dos restantes. -Dadas duas strings \( s_1 \) e \( s_2 \), o objetivo é encontrar o tamanho da maior subsequência que aparece em ambas. +O objetivo deste problema é determinar o comprimento da \textbf{maior subsequência comum} (Longest Common Subsequence - LCS) entre duas strings fornecidas. +Uma \textit{subsequência} é uma sequência que pode ser obtida a partir de uma string original removendo-se zero ou mais caracteres, sem alterar a ordem relativa dos caracteres restantes. +Dadas duas strings \( s_1 \) e \( s_2 \), deseja-se determinar \textbf{o comprimento da maior subsequência comum} e também \textbf{uma subsequência comum de comprimento máximo} presente em ambas. \Entrada -A entrada é composta por duas linhas. Na primeira linha, há dois inteiros \( n \) e \( m \) (\( 1 \leq n, m \leq 1000 \)), representando respectivamente os tamanhos das strings \( s_1 \) e \( s_2 \). +A entrada é composta por duas linhas. +Na primeira linha, há dois inteiros \( n \) e \( m \) (\( 1 \leq n, m \leq 1000 \)), representando respectivamente os tamanhos das strings \( s_1 \) e \( s_2 \). Na segunda linha, há duas strings \( s_1 \) e \( s_2 \), cada uma composta apenas por letras minúsculas do alfabeto, com tamanhos \( n \) e \( m \), respectivamente. \Saida -Imprima um único inteiro representando o comprimento da maior subsequência comum entre \( s_1 \) e \( s_2 \). +A saída consiste em duas linhas. +Na primeira linha, deve ser impresso o comprimento da maior subsequência comum. +Na segunda linha, deve ser impressa uma subsequência comum de comprimento máximo. \ExemploEntrada \begin{Exemplo} @@ -32,8 +35,8 @@ Imprima um único inteiro representando o comprimento da maior subsequência com Para as strings \( s_1 = abcde \) e \( s_2 = ace \), a maior subsequência comum é "ace", que possui tamanho 3. -Para \( s_1 = abc \) e \( s_2 = abc \), ambas as strings são idênticas, então a maior subsequência comum tem tamanho 3. +Para \( s_1 = abc \) e \( s_2 = abc \), ambas as strings são idênticas, logo a maior subsequência comum é "abc", que possui tamanho 3. -Para \( s_1 = abc \) e \( s_2 = hhh \), não há caracteres em comum, e portanto a maior subsequência comum tem tamanho 0. +Para \( s_1 = abc \) e \( s_2 = hhh \), não há caracteres em comum, e portanto a maior subsequência comum é a palavra vazia, que tem tamanho 0. \end{ProblemaAutor} \end{document} diff --git a/longest-common-subsequence/statement/description.tex b/longest-common-subsequence/statement/description.tex index 659f97b..4207f62 100644 --- a/longest-common-subsequence/statement/description.tex +++ b/longest-common-subsequence/statement/description.tex @@ -1,3 +1,3 @@ -O problema consiste em determinar o comprimento da maior subsequência comum entre duas strings. -Uma subsequência é uma sequência que pode ser obtida a partir da string original removendo-se zero ou mais caracteres, sem alterar a ordem relativa dos restantes. -Dadas duas strings \( s_1 \) e \( s_2 \), o objetivo é encontrar o tamanho da maior subsequência que aparece em ambas. +O objetivo deste problema é determinar o comprimento da \textbf{maior subsequência comum} (Longest Common Subsequence - LCS) entre duas strings fornecidas. +Uma \textit{subsequência} é uma sequência que pode ser obtida a partir de uma string original removendo-se zero ou mais caracteres, sem alterar a ordem relativa dos caracteres restantes. +Dadas duas strings \( s_1 \) e \( s_2 \), deseja-se determinar \textbf{o comprimento da maior subsequência comum} e também \textbf{uma subsequência comum de comprimento máximo} presente em ambas. diff --git a/longest-common-subsequence/statement/input.tex b/longest-common-subsequence/statement/input.tex index feb3a0f..13129e4 100644 --- a/longest-common-subsequence/statement/input.tex +++ b/longest-common-subsequence/statement/input.tex @@ -1,2 +1,3 @@ -A entrada é composta por duas linhas. Na primeira linha, há dois inteiros \( n \) e \( m \) (\( 1 \leq n, m \leq 1000 \)), representando respectivamente os tamanhos das strings \( s_1 \) e \( s_2 \). +A entrada é composta por duas linhas. +Na primeira linha, há dois inteiros \( n \) e \( m \) (\( 1 \leq n, m \leq 1000 \)), representando respectivamente os tamanhos das strings \( s_1 \) e \( s_2 \). Na segunda linha, há duas strings \( s_1 \) e \( s_2 \), cada uma composta apenas por letras minúsculas do alfabeto, com tamanhos \( n \) e \( m \), respectivamente. \ No newline at end of file diff --git a/longest-common-subsequence/statement/notes.tex b/longest-common-subsequence/statement/notes.tex index e38825d..beaf46f 100644 --- a/longest-common-subsequence/statement/notes.tex +++ b/longest-common-subsequence/statement/notes.tex @@ -1,5 +1,5 @@ Para as strings \( s_1 = abcde \) e \( s_2 = ace \), a maior subsequência comum é "ace", que possui tamanho 3. -Para \( s_1 = abc \) e \( s_2 = abc \), ambas as strings são idênticas, então a maior subsequência comum tem tamanho 3. +Para \( s_1 = abc \) e \( s_2 = abc \), ambas as strings são idênticas, logo a maior subsequência comum é "abc", que possui tamanho 3. -Para \( s_1 = abc \) e \( s_2 = hhh \), não há caracteres em comum, e portanto a maior subsequência comum tem tamanho 0. +Para \( s_1 = abc \) e \( s_2 = hhh \), não há caracteres em comum, e portanto a maior subsequência comum é a palavra vazia, que tem tamanho 0. diff --git a/longest-common-subsequence/statement/output.tex b/longest-common-subsequence/statement/output.tex index 7a38938..20353ff 100644 --- a/longest-common-subsequence/statement/output.tex +++ b/longest-common-subsequence/statement/output.tex @@ -1 +1,3 @@ -Imprima um único inteiro representando o comprimento da maior subsequência comum entre \( s_1 \) e \( s_2 \). +A saída consiste em duas linhas. +Na primeira linha, deve ser impresso o comprimento da maior subsequência comum. +Na segunda linha, deve ser impressa uma subsequência comum de comprimento máximo. \ No newline at end of file diff --git a/longest-common-subsequence/statement/tutorial.tex b/longest-common-subsequence/statement/tutorial.tex index fb768e7..992fa13 100644 --- a/longest-common-subsequence/statement/tutorial.tex +++ b/longest-common-subsequence/statement/tutorial.tex @@ -51,4 +51,49 @@ dp[0][j] = 0 \quad \forall j \ge 0 dp[i][0] = 0 \quad \forall i \ge 0 \] -Isto representa que, se uma das strings tiver tamanho zero, nenhuma subsequência comum pode ser formada. \ No newline at end of file +Isto representa que, se uma das strings tiver tamanho zero, nenhuma subsequência comum pode ser formada. + +\subsection{Recuperação da Subsequência Comum} + +Após o preenchimento da matriz \( dp \), o valor \( dp[n][m] \) fornece o comprimento da maior subsequência comum entre \( s_1 \) e \( s_2 \). +No entanto, para obter também a subsequência em si, é necessário realizar um processo de \textit{backtracking} sobre a matriz. + +A ideia consiste em iniciar a partir da posição \( (n, m) \) da matriz e caminhar em direção à origem. +Em cada passo: + +\begin{itemize} + \item Se \( s_1[i] = s_2[j] \), então este caractere faz parte da LCS. Nesse caso, retrocedemos para \( (i-1, j-1) \). + \item Caso contrário, avançamos para o vizinho que contém o maior valor entre \( dp[i-1][j] \) e \( dp[i][j-1] \), pois esse vizinho indica o caminho que manteve o comprimento máximo da subsequência. +\end{itemize} + +Como a subsequência é reconstruída de trás para frente, os caracteres encontrados devem ser adicionados no início da string resultante. + +O algoritmo para recuperar uma subsequência comum de comprimento máximo é o seguinte: + +\begin{verbatim} +int i = n; // ponteiro para s1 +int j = m; // ponteiro para s2 +string lcs = ""; // subsequência comum sendo reconstruída + +// Enquanto ainda houver caracteres a considerar +while (i > 0 && j > 0) { + + // Caso 1: os caracteres são iguais → fazem parte da LCS + if (s1[i - 1] == s2[j - 1]) { + lcs = s1[i - 1] + lcs; // adiciona no início da string + i--; + j--; + } + // Caso 2: se o valor de cima é maior, movemos para cima + else if (dp[i - 1][j] > dp[i][j - 1]) { + i--; + } + // Caso 3: caso contrário, movemos para a esquerda + else { + j--; + } +} + +\end{verbatim} + +Ao final desse processo, a string \texttt{lcs} conterá uma maior subsequência comum entre as duas strings. \ No newline at end of file