Diff Checker: LCS, o mesmo problema que o Git resolve por trás das cenas
Comparar dois textos linha a linha e destacar diferenças é, por trás da
interface simples, uma instância do problema clássico de ciência da
computação chamado Longest Common Subsequence (LCS,
maior subsequência comum) — encontrar a maior sequência de linhas que
aparece, na mesma ordem relativa, em ambos os textos. As linhas que não
fazem parte dessa subsequência comum são exatamente as que mudaram
(adicionadas ou removidas). Este comparador resolve o problema por
programação dinâmica, construindo uma tabela de comprimentos de
subsequência comum célula a célula — a mesma técnica algorítmica usada
(com otimizações adicionais) pelo git diff e por
praticamente qualquer ferramenta de comparação de texto de propósito
geral.
Por que diff de linha não é o mesmo que diff de caractere
Este comparador opera em granularidade de linha — a unidade mínima de comparação é uma linha inteira do texto, não um caractere individual. Isso significa que uma linha com uma única palavra alterada é reportada como "linha removida + linha adicionada" inteira, não como um destaque preciso apenas da palavra que mudou. Para a maioria dos casos de uso práticos (comparar versões de um arquivo de configuração, um trecho de código, um texto revisado), diff de linha é o nível de granularidade certo — é como o Git mostra diffs por padrão — mas para comparar prosa onde uma única palavra mudou dentro de um parágrafo longo, diff de caractere ou de palavra seria mais preciso (um algoritmo relacionado, mas com custo computacional maior para textos longos).
Por que a ordem das linhas afeta o resultado do diff
Um caso de borda importante para entender o algoritmo: mover um bloco de linhas de lugar (sem alterar o conteúdo delas) é, do ponto de vista de LCS, indistinguível de remover o bloco de um lugar e adicionar um bloco idêntico em outro — o algoritmo não tem noção de "movimentação" como uma operação própria, só de linhas presentes ou ausentes na subsequência comum. É por isso que reorganizar parágrafos ou blocos de código, mesmo sem mudar uma letra sequer do conteúdo, aparece num diff como remoções e adições, não como uma única operação de "mover".