Comment trouver le plus petit sous-chaîne qui contient tous les caractères d'une chaîne de caractères?
J'ai récemment rencontré une question intéressante sur les cordes. Supposons que vous êtes donné des éléments suivants:
Input string1: "this is a test string"
Input string2: "tist"
Output string: "t stri"
Donc, étant donné ci-dessus, comment puis-je m'approche vers la recherche de la plus petite sous-chaîne de chaîne1 qui contient tous les caractères de la chaîne 2?
- Devrait chaîne2 être rist ou tisr? Et dans ce cas ne serait pas la sortie "st str"?
- mot2 est donné comme "tiste" et qu'il devrait être. Si vous dites "rist" ou "tisr" que votre réponse "st str" ne contient pas "je".
- Oh, je vois, je pensais que le " r " a été mal puisqu'il n'était pas dans chaîne2 mais vous dites qu'elle doit contenir tous de string2, mais peuvent également contenir d'autres lettres...
- oui, exactement!
- faire des doublons dans
string2
doivent être pris en compte ainsi? parce que sinon la plus courte chaîne ayanttist
dansstring1
estthis
oustri
Vous devez vous connecter pour publier un commentaire.
Vous pouvez faire un histogramme de balayage dans
O(N+M)
temps etO(1)
espace oùN
est le nombre de caractères dans la première chaîne etM
est le nombre de caractères dans la seconde.Il fonctionne comme ceci:
hist2[ s2[i] ]++
).Noter qu'en variant la case que vous utilisez sur l'histogramme condition, vous pouvez choisir d'avoir le même jeu de caractères que la deuxième chaîne, ou au moins autant de caractères de chaque type. (C'est juste la différence entre
a[i]>0 && b[i]>0
eta[i]>=b[i]
.)Vous pouvez accélérer l'histogramme vérifie si vous gardez une trace de la condition n'est pas satisfaite lorsque vous essayez de le satisfaire, et de vérifier que la chose que vous décrémenter quand vous êtes à essayer de le casser. (Sur l'accumulation initiale, vous comptez combien d'articles que vous avez satisfait, et l'augmentation de compter chaque fois que vous ajoutez un nouveau personnage qui prend la condition de false à true.)
O(|set(M)|)
peut-être, où|set(M)|
est le nombre de caractères dansM
.Pour voir plus de détails, y compris le code de travail, vérifiez mon blog à:
http://www.leetcode.com/2010/11/finding-minimum-window-in-s-which.html
Pour aider à illustrer cette approche, j'ai un exemple: mot1 =
"acbbaca"
et string2 ="aba"
. Ici, nous utilisons également le terme de "fenêtre", ce qui signifie un bloc contigu de caractères à partir de mot1 (pourrait être interchangeable avec le terme de sous-chaîne).L'idée est basée principalement sur l'aide de deux pointeurs (de début et de fin de la position de la fenêtre) et de deux tables (needToFind et hasFound) en traversant chaîne1. needToFind stocke le nombre total de caractères dans mot2 et hasFound stocke le nombre total d'un personnage rencontré jusqu'à présent. Nous utilisons également un nombre variable pour stocker le nombre de caractères dans chaîne2 qui a rencontré jusqu'à présent (pas de comptage de caractères où hasFound[x] dépasse needToFind[x]). Lorsque le comte est égal à chaîne2 longueur, nous savons qu'une fenêtre valide est trouvé.
Chaque fois que l'on avance la fin pointeur vers un élément x), on incrémente hasFound[x] par un. Nous avons également incrémenter compteur d'une unité si hasFound[x] est inférieure ou égale à needToFind[x]. Pourquoi? Lorsque la contrainte est satisfaite (c'est-count est égal à chaîne2 de la taille), nous avons immédiatement commencer à l'avance du curseur de droite que possible, tout en maintenant la contrainte.
Comment vérifier si c'est le maintien de la contrainte? Supposons que commencer pointe vers un élément x, on vérifie si hasFound[x] est plus grand que needToFind[x]. Si elle l'est, on peut décrémenter hasFound[x] par l'un et l'avancement de commencer pointeur sans casser la contrainte. Sur l'autre main, si elle n'est pas, nous nous arrêtons immédiatement au titre de l'avancement de commencer pointeur brise la fenêtre de contrainte.
Enfin, on vérifie si le minimum de la longueur de la fenêtre est moins que le minimum actuel. Mise à jour le minimum si un nouveau minimum est trouvé.
Essentiellement, l'algorithme trouve la première fenêtre qui satisfait à la contrainte, puis continuer à maintenir la contrainte tout au long de.
Voici un O(n) solution. L'idée de base est simple: pour chaque indice de départ, trouver le moins que l'index de fin, tels que la sous-chaîne contient toutes les lettres. Le truc, c'est que le moins se terminant augmentation de l'indice au cours de la fonction, donc avec un peu de support de structure de données, nous considérons que chaque personnage au plus deux fois.
En Python:
i
marques de la queue de la sous-chaîne etj
marques de la tête. @algorithmist: beau travail, à venir avec code toujours aussi légèrement plus vite que je suis venu avec une description!J'ai reçu la même question de l'entrevue. Je suis une C++ candidats, mais j'étais dans une position de code relativement rapide en JAVA.
Java [Avec L'Aimable Autorisation De Sumod Mathilakath]
C++ [avec l'aimable autorisation de sundeepblue]
Erlang [avec l'aimable autorisation de wardbekker]
REF:
Jetez un oeil à ceci: les
Modifier: apparemment il y a un algorithme O(n) (cf. algorithmist de réponse). Évidemment, cela avoir cette volonté de battre l' [naïf] de référence décrit ci-dessous!
Trop mal je dois y aller... je suis un peu méfiant que nous pouvons obtenir de O(n). Je vais vérifier demain pour voir les gagnants 😉 amusez-vous!
Provisoire algorithme:
L'idée générale est de manière séquentielle essayer et utiliser un caractère de str2 trouvé dans str1 comme le début d'une recherche (dans les deux/les deux directions) de toutes les autres lettres de str2. En gardant une "longueur de correspondre au mieux à la mesure de la" valeur, nous pouvons abandonner les recherches lorsqu'ils dépassent cette. D'autres heuristiques peut probablement être utilisé pour annuler sous-optimale (jusqu'à présent) des solutions. Le choix de l'ordre de départ des lettres dans str1 choses encore; il est suggéré de commencer avec la lettre(s) de str1 qui ont la plus faible compter et à essayer avec les autres lettres, une augmentation de compter, dans les tentatives ultérieures.
Ici est l'implémentation Java
Voici le Test Junit
C'est une approche à l'aide de nombres premiers pour éviter une boucle, et de le remplacer avec les multiplications. Plusieurs autres optimisations mineures peuvent être apportées.
Attribuer un unique nombre premier de l'un des personnages que vous souhaitez trouver, et
1
à la inintéressant caractères.Trouver le produit d'une chaîne correspondante en multipliant le nombre premier avec le nombre d'occurrences qu'elle doit avoir. Maintenant, ce produit ne peut être trouvée que si les mêmes facteurs premiers sont utilisés.
De la recherche la chaîne de caractères à partir du début, en multipliant les respectifs le premier numéro que vous vous déplacez dans l'exécution d'un produit.
Si le nombre est plus grand que le bon somme, supprimer le premier caractère et de diviser son premier numéro de votre produit.
Si le nombre est inférieur à la bonne somme, inclure le caractère suivant et de se multiplier dans votre produit.
Si le nombre est le même que le bon somme que vous avez trouvé une correspondance, faites glisser début et à la fin au caractère suivant et continuer à chercher pour les autres matches.
Décider laquelle des matches est le plus court.
Gist
C# De Mise En Œuvre:
J'ai mis en place à l'aide de Python3 en O(N) efficacité:
JavaScript solution en bruteforce façon:
JS:
Code Java pour l'approche discuté ci-dessus: