Dadas n strings, uma delas é uma substring de outra?

9

Suponha que recebamos uma coleção de strings, S 1 , ... , S n . Gostaria de saber se alguma dessas strings é uma substring de qualquer outra string da coleção. Em outras palavras, eu gostaria de um algoritmo para a seguinte tarefa:nS1,,Sn

Entrada: S1,,Sn

Saída: tal que S i é uma subsequência de S j e i j , ou nenhum, se não, tais i , j existemi,jSiSjiji,j

Existe um algoritmo eficiente para isso?

Se substituirmos "substring" por "prefix", existe um algoritmo eficiente (classifique as strings, faça uma varredura linear para comparar as strings adjacentes; a classificação garantirá que as substrings sejam adjacentes). Mas parece mais desafiador testar se uma string é uma substring de outra string. Um algoritmo ingênuo é iterar sobre todos os pares , mas isso requer Θ ( n 2 ) testes de substring. Existe um algoritmo mais eficiente?i,jΘ(n2)

Acho que poderíamos chamar isso de "teste de substring de todos os pares", ou algo assim.

Meu objetivo final é remover a coleção para que nenhuma string seja uma substring de qualquer outra, removendo cada uma que é uma substring de outra coisa na coleção.

DW
fonte
Dica: matriz de sufixo.
Pseudônimo
Como observação lateral, não está correto se você remover substrings conforme os encontra. Será menos. Além disso, você deve classificar por comprimento, pois uma sequência mais longa não pode aparecer em uma sequência mais curta. Novamente Θ ( n 2 ) está errado aqui. Θ(n2)Θ(n2)
Alexis Wilke #
@AlexisWilke, está correto: esse é o número de testes de substring no pior caso (o pior caso é quando nenhuma string é um substring de qualquer outra). A classificação por comprimento fornece apenas um fator de dois, o que não afeta os assintóticos. Θ(n2)
DW

Respostas:

6

Você pode construir uma árvore de sufixos em tempo linear e verificar se há um nó interno que corresponde a uma cadeia completa (tempo constante por nó).

Mais detalhadamente, suponha que recebamos as strings .s1,,snΣ

  1. Crie uma árvore de sufixos (generalizada) de com n marcadores de terminal distintos em pares $ 1 , , $ nΣ .s1$1,s2$2,,sn$nn$1,,$nΣ

    Usando o algoritmo de Ukkonen , isso pode ser feito em tempo linear; linear na soma de todos os comprimentos de string.

  2. Supondo que você rotule as folhas com se elas representam o sufixo s i [ j . . | s i | ] de s i , atravesse a árvore e encontre as n folhas rotuladas ( i , 0 ) , ou seja, as folhas que correspondem às seqüências completas.(i,j)si[j..|si|]sin(i,0)

    Isso leva tempo linear no tamanho da árvore, que é linear no tamanho da entrada.

  3. (i,0)$i(i,0)

    Isso novamente leva tempo linear.

Os marcadores terminais distintos não são realmente necessários; uma única usada para finalizar todas as seqüências é suficiente, desde que você permita vários rótulos por folha.

Rafael
fonte