web-dev-qa-db-fra.com

Trouver un "trou" dans une liste de chiffres

Quel est le moyen le plus rapide de trouver le premier (petit) entier qui n'existe pas dans une liste donnée de non traité entiers (et qui est supérieur à la plus petite valeur de la liste)?

Mon approche primitive les trite et entrez dans la liste, y a-t-il une meilleure façon?

14
Fabian Zeindl

En supposant que vous signiez "entier" lorsque vous dites "nombre", vous pouvez utiliser un bitvector de taille 2 ^ N, où N est le nombre d'éléments (disons que votre gamme comprend des entiers compris entre 1 et 256, vous pouvez utiliser un 256- Bit, ou 32 octets, bitvector). Lorsque vous rencontrez un entier dans la position N de votre gamme, définissez le nième bit.

Lorsque vous avez fini d'énumérer la collection d'entiers, vous ithéez sur les bits de votre bitvector, à la recherche de la position de tous les bits 0. Ils correspondent maintenant à la position N de vos entiers manquants.

Ceci est O (2 * N), donc O(N) et probablement plus efficace de mémoire que de trier toute la liste.

29
JasonTrue

Si vous triez d'abord la liste complète, vous garantissez le pire-guichet. De plus, votre choix d'algorithme de tri est essentiel.

Voici comment j'approcherais ce problème:

  1. Utilisez un Trio de tas , concentrez-vous sur les éléments les plus petits des éléments de la liste.
  2. Après chaque échange, voyez si vous avez une lacune.
  3. Si vous trouvez un espace, alors return: vous avez trouvé votre réponse.
  4. Si vous ne trouvez pas d'espace, continuez à échanger.

Voici une Visualisation d'un tris de tas .

4
Jim G.

Juste pour être ésotérique et "intelligent", dans le cas particulier de la matrice ayant un seul "trou", vous pouvez essayer une solution xor:

  • Déterminer la plage de votre tableau; Ceci est fait en définissant une variable "max" et "min" au premier élément du tableau, et pour chaque élément après cela, si cet élément est inférieur au minor ou supérieur au Max, réglez le min ou max sur la nouvelle valeur.
  • Si la plage est inférieure à la cardinalité de l'ensemble, il n'y a qu'un seul "trou" afin que vous puissiez utiliser XOR.
  • Initialiser une variable entière x à zéro.
  • Pour chaque entier de min de min à max inclusivement, XOR=== cette valeur avec x et stocker le résultat dans X.
  • Maintenant XOR chaque entier dans le tableau avec X, stocke chaque résultat successif à x comme avant.
  • Lorsque vous avez terminé, X sera la valeur de votre "trou".

Cela fonctionnera dans environ 2n fois similaire à la solution Bitvector, mais nécessite moins d'espace mémoire pour tout N> Tailleof (INT). Cependant, si le tableau a plusieurs "trous", X sera le XOR "somme" de tous les trous, qui sera difficile ou impossible à séparer dans les valeurs de trou réelles. Dans ce cas Vous revenez à une autre méthode, telle que les approches "pivot" ou "bitvector" des autres réponses.

Vous pouvez récupérer cela aussi en utilisant quelque chose de similaire à la méthode de pivotement pour réduire davantage la complexité. Réorganisez la matrice à base d'un point de pivotement (qui sera le maximum du côté gauche et le min de droite; ce sera trivial pour trouver le max et le min de la maquette complète tout en pivotant). Si le côté gauche du pivot a un ou plusieurs trous, se recueille sur ce côté seulement; sinon recueillir de l'autre côté. À tout moment où vous pouvez déterminer, il n'y a qu'un seul trou, utilisez la méthode XOR pour le trouver (qui devrait être globalement moins chère que de continuer à pivoter jusqu'à une collection de deux éléments avec trou connu, qui est le boîtier de base de l'algorithme pivot pur).

4
KeithS

La plupart des idées ici ne sont pas plus que de trier. La version Bitvector est un garets plats. La sorte de tas a également été mentionné. Il se résume essentiellement à choquer le bon algorithme de tri qui dépend des exigences de temps/d'espace et également sur la plage et le nombre d'éléments.

À mon avis, l'utilisation d'une structure de tas est probablement la solution la plus générale (un tas vous donne essentiellement les plus petits éléments de manière efficace sans tri complet).

Vous pouvez également analyser d'abord les approches qui recherchent d'abord les plus petits numéros, puis numérisent pour chaque entiers plus grand que cela. Ou vous trouvez les 5 plus petits chiffres en espérant que la volonté ait un écart.

Tous ces algorithmes ont leur force en fonction des caractéristiques d'entrée et des exigences du programme.

1
Gerenuk

Non, pas vraiment. Étant donné que tout numéro non encore analysé pourrait toujours être celui qui remplit un "trou" donné, vous ne pouvez pas éviter de numériser chaque nombre au moins une fois et de les comparer à ses voisins possibles. Vous pourriez probablement accélérer les choses en construisant un arbre binaire, puis la traverser de gauche à droite jusqu'à ce qu'un trou soit trouvé, mais cela est essentiellement à la fois de la complexité de la même période que le tri. Et vous ne pourrez probablement pas venir avec quoi que ce soit plus rapidement que Timsort .

1
pillmuncher

Je crois que je suis venu avec quelque chose qui devrait fonctionner en général et efficacement si vous êtes assuré de ne pas avoir des doublons * (cependant, il devrait être extensible à un nombre quelconque de trous et une plage de nombres entiers).

L'idée derrière cette méthode est comme quicksort dans la mesure où l'on trouve un pivot et une partition autour d'elle, RECURSE puis sur le côté (s) avec un trou. Pour voir quels côtés ont le trou, nous trouvons les plus bas et plus grand nombre, et de les comparer avec le pivot et le nombre de valeurs de ce côté. Dis le pivot est de 17 et le nombre minimum est de 11. S'il n'y a pas de trous, il devrait y avoir 6 numéros (11, 12, 13, 14, 15, 16, 17). S'il y a 5, nous savons qu'il ya un trou de ce côté et nous pouvons récursif sur tout ce côté pour le trouver. Je vais avoir du mal à expliquer plus clairement que, si nous allons prendre un exemple.

15 21 10 13 18 16 22 23 24 20 17 11 25 12 14

Pivot:

10 13 11 12 14 |15| 21 18 16 22 23 24 20 17 25

15 est le pivot, indiqué par des tuyaux (||). Il y a 5 chiffres sur le côté gauche du pivot, comme il devrait y avoir (15 - 10), et 9 à droite, où il devrait y avoir 10 (25-15). Nous avons donc RECURSE sur le côté droit; nous constatons que la limite précédente était de 15 dans le cas où le trou est adjacent (16).

[15] 18 16 17 20 |21| 22 23 24 25

Maintenant, il y a 4 chiffres sur le côté gauche, mais il devrait y avoir 5 (21-16). Nous avons donc là une récursion, et encore, nous noterons la borne précédente (entre parenthèses).

[15] 16 17 |18| 20 [21]

Le côté gauche présente les chiffres corrects 2 (18 - 16), mais le droit a 1 au lieu de deux (20 - 18). En fonction de nos conditions de fin, on pourrait comparer le nombre 1 des deux côtés (18, 20) et voir que 19 est manquant ou récursif une fois de plus:

[18] |20| [21]

Le côté gauche a une taille de zéro, avec un écart entre le pivot (20) et lié précédente (18), de sorte que 19 est le trou.

*: S'il y a des doublons, vous pouvez probablement utiliser un ensemble de hachage pour les supprimer dans O(N) temps, en gardant la méthode globale O (N), mais pourrait prendre plus de temps que d'utiliser une autre méthode.

0
Kevin

Une solution qui n'utilise pas de stockage supplémentaire ou suppose la largeur (32 bits) d'entiers.

  1. Dans une passe linéaire, trouvez le plus petit nombre. Permet d'appeler cette "min". O(n) Complexité du temps.

  2. Choisissez un élément de pivot aléatoire et faites une partition de style QuicksTort.

  3. Si le pivot s'est terminé dans la position = ("pivot" - "min"), puis recueille sur le côté droit de la partition, sinon recueille sur le côté gauche de la partition. L'idée ici est que s'il n'y a pas de trous depuis le début, le pivot serait à ("pivot" - "min") Th position, de sorte que le premier trou devrait mentir à la droite de la partition et inversement.

  4. Le boîtier de base est un tableau d'un élément et le trou réside entre cet élément et la suivante.

La complexité totale totale de fonctionnement attendue est O(n) (8 * N avec les constantes) et le pire des cas est O (n ^ 2). L'analyse de la complexité temporelle pour un problème similaire peut être trouvée ICI .

0
aufather