Algorithme rapide pour la recherche de sous-chaînes dans une chaîne de caractères
J'aimerais un algorithme efficace (ou bibliothèque) que je peux utiliser en Java pour la recherche de sous-chaînes dans une chaîne de caractères.
Ce que je voudrais faire c'est:
Donné une chaîne d'entrée - INSTR:
"BCDEFGH"
Et un ensemble de candidats cordes - CAND:
"AB", "CDE", "FG", "H", "IJ"
Trouver tout CAND chaînes qui correspondent comme des sous-chaînes dans INSTR
Dans cet exemple, je pourrait correspondre à "CDE", "FG" et "H" (mais pas "AB" et "IJ")
Il pourrait y avoir plusieurs milliers de candidats des chaînes de caractères (ACDN), mais plus important encore, je vais faire cette recherche plusieurs millions de fois, donc j'ai besoin d'être RAPIDE.
J'aimerais travailler avec des tableaux de char. Aussi, je ne suis pas intested dans les solutions architecturales, comme la distribution de la recherche - tout le plus efficace de la fonction/l'algorithme pour le faire localement.
En outre, toutes les chaînes de CAND et INSTR seront tous relativement faible (< 50 caractères) - c'est à dire la chaîne de caractères de l'INSTRUMENT n'est PAS longue par rapport à la candidat à cordes.
Mise à jour je devrais l'avoir mentionné, l'ensemble de l'ACDN chaînes est invariant à travers toutes les valeurs des INSTR.
Mise à jour j'ai seulement besoin de savoir qu'il y avait un match et je n'ai pas besoin de savoir ce que le match a été.
Dernière Mise À Jour
J'ai opté pour tenter AhoCorsick et de Rabin-Karp, en raison de la simplicité de mise en œuvre.
Parce que j'ai de longueur variable des modèles, j'ai utilisé une version modifiée de Rabin-Karp qui hache les n premiers caractères de chaque modèle, où n est la longueur du plus petit modèle, N est la longueur de mon roulement de chaîne de fenêtre de recherche.
Pour l'Aho Corsick j'ai utilisé cette
Dans mon test j'ai cherché pour 1000 modèles dans les deux documents news articles en papier, en moyenne sur 1000 itérations etc...
Normalisé fois pour terminer étaient:
AhoCorsick: 1
RabinKarp: 1.8
Naïf de Recherche (vérifiez chaque motif & utiliser des chaînes de caractères.contient): 50
*Certaines ressources décrivant les algos mentionnés dans les réponses ci-dessous:
http://www.seas.gwu.edu/~simhaweb/cs151/lectures/module5/module5.html
http://www.cs.princeton.edu/courses/archive/spr09/cos226/lectures/18SubstringSearch-2x2.pdf
http://www-igm.univ-mlv.fr/~lecroq/string/index.html*
- Combien de temps sont les chaînes d'entrée par rapport à la candidat à cordes?
- Ils sont courts. Les chaînes d'entrée sont généralement moins de 40 caractères, que les candidats sont des chaînes de caractères.
- mais il peut y avoir plusieurs milliers de candidats cordes, et je veux le faire à plusieurs reprises sur de nombreuses chaînes d'entrée des millions de fois.
- Étant donné les détails d'un FSM est probablement votre meilleur choix.
- Curieux de savoir à quoi vous attendre en tant que sortie. C'est de savoir que l'un a été trouvé assez bon ou avez-vous besoin de savoir ce qui a été trouvé? Avez-vous besoin de savoir combien de fois chaque sous-chaîne a été trouvé?
- Oui, un match est assez bon avec un simple "vrai/faux" et pas les autres informations nécessaires.
Vous devez vous connecter pour publier un commentaire.
Lire sur le Aho-Corasick algorithme et la Rabin-Karp algorithme.
Si l'entrée n'est pas trop gros, vous ne voulez pas répéter la recherche de nombreuses fois et vous n'avez pas beaucoup de modèles, il pourrait être une bonne idée d'utiliser un modèle unique algorithme plusieurs fois. Le Article de wikipédia sur les algorithmes de recherche donne de nombreux algorithmes pour la course et de prétraitement fois.
Implémentations:
Présentations:
Convertir l'ensemble des candidats chaînes dans un déterministe finite state automaton puis exécutez à travers la chaîne d'entrée dans le temps linéaire. La conversion d'une chaîne unique dans un DFS est bien couverte dans la norme des livres. Vous pouvez convertir un ensemble de chaînes par construire un automate non déterministe et puis determinizing il. Qui peut créer exponentielle de blow-up, dans le pire des cas, la taille de l'automate, mais la recherche par la suite est rapide, surtout si l'objectif de la chaîne est longue et les candidats court qui va bien travailler.
C'est ce que les expressions régulières sont pour. Comme indiqué ci-dessus, automates d'états finis sont ce à quoi vous avez besoin, mais c'est exactement la façon dont une norme regexp-matcher est mis en œuvre.
En java, vous pouvez écrire quelque chose comme:
la méthode
escape
doit s'échapper tous les caractères qui ont une signification particulière dans une regexp.Rabin-Karp plusieurs modèle de recherche semble être le plus rapide.
Vous voudrez peut-être regarder dans Aho-Corasick algorithme et liées à des algorithmes. Je ne sais pas du tout bibliothèques de mise en œuvre de cette, désinvolte, mais c'est la façon classique de la résolution de ce problème.
Également de vérifier la Boyer-Moore algorithme pour une seule chaîne de filtrage.
On peut tirer avantage de la petite taille (< 50 caractères) des chaînes afin de construire un super rapide algo pour ce cas, le coût de la mémoire.
Nous pouvons hachage de tous les sous-chaînes possible de l'INSTRUMENT dans une table de hachage d'un temps, d'un coût de O(n^2). Alors quel que soit le nombre de CAND chaînes, la recherche sera O(1). Il vaut la peine pour un très grand nombre de CAND chaînes.
Si l'INSTRUMENT est grand, alors nous pouvons construire un suffixe tableau et non pas à les trier, de sorte que le premier élément est le plus long (=N) et le dernier élément est le dernier char de l'INSTRUMENT. Maintenant, pour chaque CANDIDAT de la chaîne, seulement rechercher depuis le haut aussi longtemps que la longueur(ACDN) <= longueur(suffixe). Chacune de ces comparaisons seront O(n).
1
et2
de votre expression et vous êtes de gauche avecO((n)(n))
qui est le même queO(n^2)
.Une autre solution est d'utiliser un suffixe tableau pour la INSTR.
Depuis le INSTR est petite, vous pouvez les trier avec tri à bulles.
Ensuite, vous pouvez rechercher un CAND chaîne en O(logN) temps,
où N = longueur(suffix_array) = longueur(INSTR).
Ici sont certains de la mise en œuvre rapide de la Chaîne d'algorithmes de recherche en Java.