Eu estou procurando um algoritmo de correspondência de seqüência k-incompatibilidade rápida. Dada uma string padrão P de comprimento me uma string de texto T de comprimento n, preciso de um algoritmo rápido (tempo linear) para encontrar todas as posições em que P corresponde a uma subcadeia de T com no máximo k incompatibilidades. Isso é diferente do problema das diferenças k (distância de edição). Uma incompatibilidade implica a subcadeia e o padrão tem uma letra diferente na maioria das k posições. Eu realmente preciso apenas de k = 1 (no máximo 1 incompatibilidade), portanto, um algoritmo rápido para o caso específico de k = 1 também será suficiente. O tamanho do alfabeto é 26 (texto em inglês que não diferencia maiúsculas de minúsculas); portanto, o requisito de espaço não deve aumentar muito rapidamente com o tamanho do alfabeto (por exemplo, acredito que o algoritmo FAAST ocupa espaço exponencial no tamanho do alfabeto e, portanto, é adequado apenas para sequências de proteínas e genes).
Uma abordagem dinâmica baseada em programação tenderá a ser O (mn) no pior caso, o que será muito lento. Acredito que há modificações no algoritmo de Boyer-Moore para isso, mas não sou capaz de colocar minhas mãos em tais documentos. Não tenho assinatura para acessar periódicos ou publicações acadêmicas; portanto, todas as referências deverão ser de domínio público.
Eu gostaria muito de receber dicas, referências a documentos disponíveis gratuitamente ou o próprio algoritmo para esse problema.
Respostas:
Matrizes de sufixo podem ser usadas para esse problema. Eles contêm as posições iniciais de cada sufixo da sequência classificada em ordem lexicográfica. Mesmo que eles possam ser construídos ingenuamente na complexidade , existem métodos para construí-los na complexidade . Veja, por exemplo, isto e isto . Vamos chamar esse conjunto de sufixos SA.Θ ( n )O(nlogn) Θ(n)
Depois que a matriz de sufixos foi construída, precisamos construir uma matriz LCP (Longest Common Prefix) para a matriz de sufixos. A matriz LCP armazena o comprimento do prefixo comum mais longo entre dois prefixos consecutivos na matriz de sufixos (sufixos consecutivos lexicográficos). Assim, o LCP [i] contém o comprimento do maior prefixo comum entre SA [i] e SA [i + 1]. Essa matriz também pode ser construída em tempo linear: veja aqui , aqui e aqui algumas boas referências.
Agora, para calcular o comprimento do prefixo mais longo comum a quaisquer dois sufixos na árvore de sufixos (em vez de sufixos consecutivos), precisamos usar alguma estrutura de dados RMQ . Mostrou-se nas referências acima (e pode ser visto facilmente se a matriz é visualizada como uma árvore de sufixos), que o comprimento da mais longa prefixo comum entre dois sufixos tendo posições e ( ) na matriz de sufixo , pode ser obtido como . Um bom RMQ pode pré-processar a matriz em ou e responder a consultas no formato emv u < v m i n u < = k < = v - 1 L C P [ k ] L C P O ( n ) O ( n log n ) L C P [ u , v ] O ( 1 )u v u<v minu<=k<=v−1LCP[k] LCP O(n) O(nlogn) LCP[u,v] O(1) Tempo. Veja aqui um algoritmo RMQ succint e aqui um bom tutorial sobre RMQs e o relacionamento (e reduções) entre LCA e RMQs. Isso tem outra boa abordagem alternativa.
Com essas informações, construímos a matriz de sufixos e matrizes associadas (como descrito acima) para a concatenação das duas seqüências com um delimitador no meio (como T # P, onde '#' não ocorre em nenhuma das seqüências). Em seguida, podemos executar a correspondência de k de incompatibilidade de caracteres usando o método "canguru". Isso e isso explicam o método canguru no contexto das árvores de sufixos, mas também podem ser diretamente aplicados às matrizes de sufixos. Para cada índice do texto , encontre o do sufixo de começando em o sufixo de iniciando em 0. Isso fornece o local após o qual a primeira incompatibilidade ocorre ao corresponderi T LCP T i P P com . Seja esse comprimento . Pule o caractere incompatível em e e tente combinar as seqüências restantes. Ou seja, encontre novamente o de e . Repita isso até obter incompatibilidades, ou qualquer uma das seqüências termina. Cada é . Existem 's para cada índice de , dando a isso uma complexidade total de .T[i] l0 T P LCP T[i+l0+1] P[l0+1] k LCP O(1) O(k) LCP i T O(nk)
Eu usei um RMQ mais fácil de implementar, fornecendo uma complexidade total de ou se , mas também pode ser feito em como descrito acima. Pode haver outros métodos diretos para esse problema, mas essa é uma abordagem poderosa e genérica que pode ser aplicada a muitos problemas semelhantes.O(nk+(n+m)log(n+m)) O(nk+nlogn) m=O(n) O(nk)
fonte
Abaixo está um algoritmo esperado (que pode ser estendido para outro , tornando-o ). (Ainda não fiz os cálculos para provar que é assim).O(n+m) k O(nk+m)
A idéia é semelhante ao algoritmo de hash de rolamento Rabin-Karp para correspondências exatas de substring.
A idéia é separar cada sequência de comprimento em blocos de tamanho cada e calcular o hash de rolagem para cada bloco (fornecendo valores de hash) e comparar esses valores de com o padrão.m 2k m/2k 2k 2k
Permitimos no máximo desencontros nesses valores.k
Se ocorrerem mais de incompatibilidades, rejeitamos e seguimos em frente. Caso contrário, tentamos confirmar uma correspondência aproximada.k
Espero (ressalva: ainda não tentei) que isso provavelmente será mais rápido na prática e talvez mais fácil de codificar / manter do que usar uma abordagem baseada em árvore de sufixos.
fonte