J'ai eu ce problème dans une interview. Comment auriez-vous répondu?
Concevez une structure de données qui offre les opérations suivantes en temps O (1):
- insérer
- retirer
- contient
- obtenir un élément aléatoire
data-structures
guildner
la source
la source
Réponses:
Considérez une structure de données composée d'une table de hachage H et d'un tableau A. Les clés de table de hachage sont les éléments de la structure de données et les valeurs sont leurs positions dans le tableau.
puisque le tableau doit augmenter automatiquement en taille, il va être amorti O (1) pour ajouter un élément, mais je suppose que c'est OK.
la source
La recherche O (1) implique une structure de données hachée .
Par comparaison:
la source
hashtable.get((int)(Math.random()*hashtable.size()));
Cela ne vous plaira peut-être pas, car ils recherchent probablement une solution intelligente, mais parfois il vaut mieux s'en tenir à vos armes ... Une table de hachage satisfait déjà les exigences - probablement mieux dans l'ensemble que toute autre chose (bien que évidemment en constante amortie temps, et avec différents compromis avec d’autres solutions).
L'exigence qui est délicate est la sélection "d'élément aléatoire": dans une table de hachage, vous auriez besoin de rechercher ou de rechercher un tel élément.
Pour le hachage fermé / l'adressage ouvert, la probabilité qu'un compartiment donné soit occupé est
size() / capacity()
, mais surtout, cela est généralement maintenu dans une plage multiplicative constante par une implémentation de table de hachage (par exemple, la table peut être maintenue plus grande que son contenu actuel par exemple 1,2x à ~ 10x selon le réglage des performances / de la mémoire). Cela signifie qu'en moyenne, nous pouvons nous attendre à rechercher entre 1,2 et 10 seaux - totalement indépendante de la taille totale du conteneur; amorti O (1).Je peux imaginer deux approches simples (et bien d'autres plus délicates):
rechercher linéairement à partir d'un compartiment aléatoire
essayez plusieurs seaux aléatoires jusqu'à ce que vous en trouviez un rempli
Ce n'est pas une excellente solution, mais cela peut tout de même être un meilleur compromis global que les frais de mémoire et de performances liés à la maintenance d'un deuxième tableau d'index à tout moment.
la source
La meilleure solution est probablement la table de hachage + tableau, c'est vraiment rapide et déterministe.
Mais la réponse la moins bien notée (utilisez simplement une table de hachage!) Est également excellente!
Les gens n'aimeront peut-être pas ça à cause des "boucles infinies possibles", et j'ai vu des gens très intelligents avoir cette réaction aussi, mais c'est faux! Les événements infiniment improbables ne se produisent tout simplement pas .
En supposant le bon comportement de votre source pseudo-aléatoire - ce qui n'est pas difficile à établir pour ce comportement particulier - et que les tables de hachage sont toujours pleines à au moins 20%, il est facile de voir que:
Il n'arrivera jamais que getRandom () doive essayer plus de 1000 fois. Juste jamais . En effet, la probabilité d'un tel événement est de 0,8 ^ 1000, soit 10 ^ -97 - nous devrions donc le répéter 10 ^ 88 fois pour avoir une chance sur un milliard que cela se produise une fois. Même si ce programme fonctionnait à plein temps sur tous les ordinateurs de l'humanité jusqu'à la mort du Soleil, cela ne se produira jamais .
la source
Pour cette question, j'utiliserai deux structures de données
Pas :-
Code: -
- Complexité temporelle O (1). - Complexité spatiale O (N).
la source
Voici une solution C # à ce problème que j'ai trouvé il y a quelque temps quand on m'a posé la même question. Il implémente Add, Remove, Contains et Random avec d'autres interfaces .NET standard. Non pas que vous ayez jamais besoin de l'implémenter avec autant de détails lors d'une interview, mais c'est bien d'avoir une solution concrète à regarder ...
la source
ArgumentException
avec le message "Un élément avec la même clé a déjà été ajouté." sera lancé (à partir du dictionnaire d'index sous-jacent).Nous pouvons utiliser le hachage pour prendre en charge les opérations dans le temps Θ (1).
insert (x) 1) Vérifiez si x est déjà présent en effectuant une recherche de carte de hachage. 2) S'il n'est pas présent, insérez-le à la fin du tableau. 3) Ajoutez également la table de hachage, x est ajouté comme clé et le dernier index de tableau comme index.
remove (x) 1) Vérifiez si x est présent en effectuant une recherche de carte de hachage. 2) S'il est présent, recherchez son index et supprimez-le de la carte de hachage. 3) Échangez le dernier élément avec cet élément dans le tableau et supprimez le dernier élément. L'échange est effectué car le dernier élément peut être supprimé en un temps O (1). 4) Mettre à jour l'index du dernier élément de la carte de hachage.
getRandom () 1) Génère un nombre aléatoire de 0 au dernier index. 2) Renvoyez l'élément du tableau à l'index généré aléatoirement.
search (x) Recherchez x dans la carte de hachage.
la source
Bien que ce soit bien vieux, mais comme il n'y a pas de réponse en C ++, voici mes deux cents.
Voici un morceau de code client pour tester la solution.
la source
Dans C # 3.0 + .NET Framework 4, un générique
Dictionary<TKey,TValue>
est encore meilleur qu'un Hashtable car vous pouvez utiliser laSystem.Linq
méthode d'extensionElementAt()
pour indexer dans le tableau dynamique sous-jacent où lesKeyValuePair<TKey,TValue>
éléments sont stockés:Cependant, pour autant que je sache, un Hashtable (ou sa progéniture Dictionary) n'est pas une vraie solution à ce problème car Put () ne peut être amorti que O (1), pas vrai O (1), car c'est O (N ) à la limite de redimensionnement dynamique.
Y a-t-il une vraie solution à ce problème? Tout ce que je peux penser, c'est que si vous spécifiez une capacité initiale Dictionary / Hashtable d'un ordre de grandeur au-delà de ce dont vous prévoyez avoir besoin, alors vous obtenez des opérations O (1) car vous n'avez jamais besoin de redimensionner.
la source
Je suis d'accord avec Anon. À l'exception de la dernière exigence où l'obtention d'un élément aléatoire avec une équité égale est requise, toutes les autres exigences ne peuvent être satisfaites qu'à l'aide d'un seul DS basé sur le hachage. Je vais choisir HashSet pour cela en Java. Le modulo du code de hachage d'un élément me donnera le numéro d'index du tableau sous-jacent en temps O (1). Je peux l'utiliser pour ajouter, supprimer et contient des opérations.
la source
Ne pouvons-nous pas faire cela en utilisant HashSet de Java? Il fournit insérer, supprimer, rechercher tout dans O (1) par défaut. Pour getRandom, nous pouvons utiliser l'itérateur de Set qui donne de toute façon un comportement aléatoire. Nous pouvons simplement itérer le premier élément de l'ensemble sans nous soucier du reste des éléments
la source
la source
Pourquoi n'utilisons-nous pas epoch% arraysize pour trouver un élément aléatoire. Trouver la taille du tableau est O (n) mais la complexité amortie sera O (1).
la source
Je pense que nous pouvons utiliser une double liste de liens avec une table de hachage. key sera element et sa valeur associée sera node dans doublement linklist.
la source