Sequências e cadeias de matrizes

LCS, distância de edição e parentização de matrizes, com tabelas e reconstrução.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

ABCD e BACD partilham ACD como subsequência, conservando a ordem das letras e omitindo uma de cada palavra. Para encontrar uma subsequência comum de comprimento máximo, comparamos prefixos cada vez maiores e guardamos o melhor para cada par. A última letra de cada prefixo determina quais as células anteriores que precisamos de consultar.

A distância de edição usa o mesmo par de prefixos com outro objetivo: contar operações para transformar uma palavra na outra. A cadeia de matrizes usa estados por intervalos para escolher os parênteses sem mudar a ordem dos fatores. As três técnicas separam o que já está decidido do que ainda falta decidir.

Subsequência comum mais longa

Uma subsequência conserva a ordem, mas pode omitir elementos. ACD é subsequência de ABCD; não é um subvetor contíguo. A LCS de duas sequências é uma subsequência comum de comprimento máximo.

Define L[i,j]L[i,j] como o comprimento da LCS dos primeiros ii símbolos de XX e dos primeiros jj de YY. Os índices i,ji,j são comprimentos, pelo que X[i−1]X[i-1] e Y[j−1]Y[j-1] são os últimos símbolos desses prefixos.

L[i,j]={0,i=0 ou j=0,1+L[i−1,j−1],X[i−1]=Y[j−1],max⁡(L[i−1,j],L[i,j−1]),X[i−1]≠Y[j−1].L[i,j]=\begin{cases} 0,&i=0\text{ ou }j=0,\\ 1+L[i-1,j-1],&X[i-1]=Y[j-1],\\ \max(L[i-1,j],L[i,j-1]),&X[i-1]\ne Y[j-1]. \end{cases}

Quando os últimos símbolos coincidem, existe uma LCS que os emparelha, porque uma LCS que usasse uma ocorrência anterior pode deslocar esse emparelhamento para os últimos sem perder a ordem. Quando diferem, não podem ser os dois o último símbolo comum, por isso pelo menos um fica de fora e as duas exclusões cobrem as alternativas.

Para X=ABCDX=\texttt{ABCD} e Y=BACDY=\texttt{BACD}:

X\YX\backslash YvazioBACD
vazio00000
A00111
B01111
C01122
D01123

O comprimento é 3.

Para reconstruir, regista em cada célula a decisão que atinge o máximo: diagonal quando X[i−1]=Y[j−1]X[i-1]=Y[j-1], senão cima ou esquerda conforme o maior valor. Começa em (4,4)(4,4), onde D coincide: segue a diagonal e guarda D. Em (3,3)(3,3), C coincide e guarda C do mesmo modo. Em (2,2)(2,2), B≠AB\ne A e L[1,2]=L[2,1]=1L[1,2]=L[2,1]=1, um empate entre cima e esquerda: escolher cima encontra A e dá ACD, enquanto escolher esquerda encontra B e dá BCD. Inverte os símbolos guardados no fim.

O empate representa várias soluções ótimas, não um erro. As duas respostas conservam a ordem em ambas as sequências e atingem o mesmo comprimento.

O tempo e a tabela são O(∣X∣∣Y∣)O(|X||Y|). Duas linhas chegam para o comprimento, mas deixam de guardar o percurso completo de reconstrução. Uma string vazia tem LCS de comprimento zero com qualquer outra.

Distância de edição

A distância de Levenshtein é o mínimo número de inserções, remoções e substituições para transformar XX em YY. Cada operação custa 1; manter um símbolo igual custa 0. Outros custos definem outro problema.

Define D[i,j]D[i,j] para os primeiros ii símbolos de XX e os primeiros jj de YY. Temos D[i,0]=iD[i,0]=i, porque removemos todos, e D[0,j]=jD[0,j]=j, porque inserimos todos.

D[i,j]=min⁡{D[i−1,j]+1remover X[i−1],D[i,j−1]+1inserir Y[j−1],D[i−1,j−1]+[X[i−1]≠Y[j−1]]manter ou substituir.D[i,j]=\min\begin{cases} D[i-1,j]+1&\text{remover }X[i-1],\\ D[i,j-1]+1&\text{inserir }Y[j-1],\\ D[i-1,j-1]+[X[i-1]\ne Y[j-1]]&\text{manter ou substituir}. \end{cases}

O símbolo entre parênteses retos vale 1 se a condição é verdadeira e 0 se é falsa. As três linhas são as possíveis últimas operações da transformação. Não acrescentes automaticamente 1 à diagonal quando os símbolos já são iguais.

Para canto e gato, a tabela é:

X\YX\backslash Yvaziogato
vazio01234
c11234
a22123
n33223
t44323
o55432

A distância é 2. Uma transformação ótima substitui c por g e remove n. Guardar a operação escolhida permite reconstruir um alinhamento, incluindo inserções e remoções. O custo é O(∣X∣∣Y∣)O(|X||Y|) tempo e espaço, ou O(min⁡(∣X∣,∣Y∣))O(\min(|X|,|Y|)) espaço para apenas a distância.

Distância de edição de duas palavras
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int main() {
    std::string a, b;
    if (!std::getline(std::cin, a) || !std::getline(std::cin, b) ||
        a.size() > 500 || b.size() > 500) {
        std::cout << "entrada invalida\n";
        return 0;
    }
    int n = static_cast<int>(a.size()), m = static_cast<int>(b.size());
    std::vector<std::vector<int>> d(n + 1, std::vector<int>(m + 1));
    for (int i = 0; i <= n; ++i) d[i][0] = i;
    for (int j = 0; j <= m; ++j) d[0][j] = j;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            d[i][j] = std::min({d[i - 1][j] + 1, d[i][j - 1] + 1,
                               d[i - 1][j - 1] + (a[i - 1] != b[j - 1])});
    std::cout << "distancia " << d[n][m] << '\n';
}
Resultado

Executa o código para ver a saída e os gráficos.

Devolve distancia 2. Lê duas linhas, por isso uma linha vazia representa uma string vazia; mudar a entrada para \ngato deve dar 4. O exemplo limita cada linha a 500 bytes e trata bytes como símbolos. Para texto Unicode geral, um carácter pode ocupar vários bytes; seria necessário escolher e implementar uma unidade como pontos de código ou grafemas.

Distância de edição não é LCS com outra designação. Se só inserções e remoções fossem permitidas, o custo mínimo seria ∣X∣+∣Y∣−2∣LCS∣|X|+|Y|-2|LCS|. Permitir substituição a custo 1 pode baixar esse valor: a para b custa 1, e não 2.

Cadeia de matrizes

Queremos calcular A1A2⋯AnA_1A_2\cdots A_n com o menor número de multiplicações escalares. A ordem das matrizes permanece; mudamos apenas os parênteses. A multiplicação é associativa, mas a matriz intermédia e o custo dependem da parentização.

Se AiA_i tem dimensões pi−1×pip_{i-1}\times p_i, multiplicar uma matriz r×sr\times s por outra s×ts\times t custa rstrst multiplicações escalares no algoritmo usual. Define M[i,j]M[i,j] como o menor custo para a cadeia Ai⋯AjA_i\cdots A_j.

M[i,i]=0,M[i,i]=0, M[i,j]=min⁡i≤k<j(M[i,k]+M[k+1,j]+pi−1pkpj).M[i,j]=\min_{i\le k<j}\left(M[i,k]+M[k+1,j]+p_{i-1}p_kp_j\right).

A última multiplicação divide a cadeia depois de algum kk. Se um dos lados não estivesse parentizado de forma ótima, substituí-lo por um melhor preservaria as dimensões e reduziria o total. Avaliar todos os kk encontra a melhor divisão.

Preenche por comprimento crescente do intervalo. Guardar K[i,j]K[i,j], o kk vencedor, permite reconstruir recursivamente os parênteses.

Para A:5×10A:5\times10, B:10×3B:10\times3, C:3×12C:3\times12:

  • M[A,B]=5⋅10⋅3=150M[A,B]=5\cdot10\cdot3=150.
  • M[B,C]=10⋅3⋅12=360M[B,C]=10\cdot3\cdot12=360.
  • Dividir A∣BCA\mid BC dá 0+360+5⋅10⋅12=9600+360+5\cdot10\cdot12=960.
  • Dividir AB∣CAB\mid C dá 150+0+5⋅3⋅12=330150+0+5\cdot3\cdot12=330.

Escolhemos (AB)C(AB)C, custo 330, e não A(BC)A(BC), custo 960. A resposta da tabela é um plano de cálculo; a tabela não calcula os elementos do produto.

Há Θ(n2)\Theta(n^2) intervalos e até O(n)O(n) divisões por intervalo, portanto O(n3)O(n^3) tempo e O(n2)O(n^2) espaço. Com uma matriz o custo é zero. Dimensões incompatíveis tornam a cadeia inválida antes de procurar uma parentização.

Exercícios

Escolher os parênteses

A tem dimensão 8×2, B tem 2×10 e C tem 10×3. Quantas multiplicações escalares usa a melhor parentização?

Pista

Calcula os dois produtos possíveis primeiro e as dimensões que deixam.

Solução

A(BC) custa 60+48=108, com BC de dimensão 2×3. (AB)C custa 160+240=400, com AB de dimensão 8×10. A multiplicação BC produz uma matriz 2×3, e multiplicá-la por A mantém a dimensão intermédia pequena. A ordem A,B,C não muda, apenas a associação.

Erros frequentes

Somar apenas o custo da primeira multiplicação omite o produto final. Trocar A e B não é uma parentização.

Voltar à explicação
Duas medidas diferentes para palavras

Para X=ab e Y=ac, calcula o comprimento da LCS e a distância de edição com substituição de custo 1. Explica por que não podes obter esta distância só pela fórmula de inserções e remoções.

Pista

A subsequência comum pode conservar a; b e c são diferentes.

Mais uma pista

Uma substituição de b por c resolve a transformação. Remover e inserir faria duas operações.

Solução

A LCS tem comprimento 1, por exemplo a. A distância de Levenshtein é 1 por substituir b por c. A fórmula |X|+|Y|-2LCS dá 2 e corresponde à variante que só admite inserções e remoções. Com substituição a custo 1, esse resultado não é a distância pedida.

Confere a tua resposta:

  • Obtive LCS de comprimento 1.
  • Obtive distância 1 por substituição.
  • Expliquei por que a fórmula daria 2 noutra variante.

Erros frequentes

LCS mede uma subsequência, não um conjunto sem ordem. Aplicar uma fórmula de outro conjunto de operações muda o problema.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.