Étant donné n chaînes, l'une d'elles est-elle une sous-chaîne d'une autre?

9

Supposons que l'on nous donne une collection de chaînes, S 1 , , S n . Je voudrais savoir si l'une de ces chaînes est une sous-chaîne d'une autre chaîne de la collection. En d'autres termes, j'aimerais un algorithme pour la tâche suivante:nS1,,Sn

Entrée: S1,,Sn

Sortie: telle que S i est une sous-chaîne de S j et i j , ou None si aucune telle i , j n'existei,jSiSjiji,j

Existe-t-il un algorithme efficace pour cela?

Si nous remplaçons «sous-chaîne» par «préfixe», il existe un algorithme efficace (triez les chaînes, puis effectuez un balayage linéaire pour comparer les chaînes adjacentes; le tri garantira que les sous-chaînes sont adjacentes). Mais il semble plus difficile de tester si une chaîne est une sous-chaîne d'une autre chaîne. Un algorithme naïf consiste à parcourir toutes les paires , mais cela nécessite des tests de sous-chaîne Θ ( n 2 ) . Existe-t-il un algorithme plus efficace?i,jΘ(n2)

Je suppose que nous pourrions appeler cela "test de sous-chaîne toutes paires", ou quelque chose comme ça.

Mon but ultime est d'élaguer la collection afin qu'aucune chaîne ne soit une sous-chaîne d'une autre, en supprimant chacune qui est une sous-chaîne de quelque chose d'autre dans la collection.

DW
la source
Astuce: tableau de suffixes.
Pseudonyme du
En remarque, n'est pas correct si vous supprimez les sous-chaînes au fur et à mesure que vous les trouvez. Ce sera moins. En outre, vous devez trier par longueur car une chaîne plus longue ne peut pas apparaître dans une chaîne plus courte. Encore une fois, Θ ( n 2 ) a tort ici. Θ(n2)Θ(n2)
Alexis Wilke
@AlexisWilke, est correct: c'est le nombre de tests de sous-chaîne dans le pire des cas (le pire des cas est lorsqu'aucune chaîne n'est une sous-chaîne d'un autre). Le tri par longueur ne vous donne qu'un facteur de deux, ce qui n'affecte pas les asymptotiques. Θ(n2)
DW

Réponses:

6

Vous pouvez créer un arbre de suffixes en temps linéaire et vérifier s'il y a un nœud interne qui correspond à une chaîne complète (temps constant par nœud).

Plus en détail, supposons que l'on nous donne des chaînes .s1,,snΣ

  1. Construisez un arbre de suffixes (généralisé) de avec n marqueurs de terminal distincts par paire $ 1 , , $ nΣ .s1$1,s2$2,,sn$nn$1,,$nΣ

    En utilisant l'algorithme d'Ukkonen , cela peut être fait en temps linéaire; linéaire dans la somme de toutes les longueurs de chaîne.

  2. (i,j)si[j..|si|]sin(i,0)

    Cela prend du temps linéaire dans la taille de l'arbre, qui lui-même est linéaire dans la taille d'entrée.

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

    Cela prend à nouveau du temps linéaire.

Les marqueurs terminaux distincts ne sont pas vraiment nécessaires; une seule utilisée pour terminer toutes les chaînes est tout à fait suffisante tant que vous autorisez plusieurs étiquettes par feuille.

Raphael
la source