J'ai eu ce problème lors d'une interview avec Microsoft.
Étant donné un tableau d'entiers aléatoires, écrivez un algorithme en C qui supprime les nombres dupliqués et renvoie les nombres uniques dans le tableau d'origine.
Par exemple, entrée: {4, 8, 4, 1, 1, 2, 9}
sortie:{4, 8, 1, 2, 9, ?, ?}
Une mise en garde est que l'algorithme attendu ne devrait pas exiger que le tableau soit trié en premier. Et lorsqu'un élément a été supprimé, les éléments suivants doivent également être déplacés vers l'avant. Quoi qu'il en soit, la valeur des éléments à la queue du tableau où les éléments ont été décalés vers l'avant est négligeable.
Mise à jour: le résultat doit être renvoyé dans le tableau d'origine et la structure de données d'assistance (par exemple, table de hachage) ne doit pas être utilisée. Cependant, je suppose que la préservation de l'ordre n'est pas nécessaire.
Mise à jour 2: Pour ceux qui se demandent pourquoi ces contraintes peu pratiques, c'était une question d'entretien et toutes ces contraintes sont discutées pendant le processus de réflexion pour voir comment je peux trouver des idées différentes.
la source
Réponses:
Que diriez-vous:
Doit être O (n ^ 2) ou moins.
la source
Une solution suggérée par ma copine est une variante du tri par fusion. La seule modification est que lors de l'étape de fusion, ne tenez pas compte des valeurs dupliquées. Cette solution serait également O (n log n). Dans cette approche, le tri / suppression de duplication sont combinés. Cependant, je ne suis pas sûr que cela fasse une différence.
la source
J'ai déjà posté ceci une fois sur SO, mais je vais le reproduire ici car c'est plutôt cool. Il utilise le hachage, créant quelque chose comme un jeu de hachage en place. Il est garanti qu'il est O (1) dans l'espace axillaire (la récursion est un appel de queue), et est généralement de complexité temporelle O (N). L'algorithme est le suivant:
Cela peut être montré comme O (N) à condition qu'il n'y ait pas de scénario pathologique dans le hachage: même s'il n'y a pas de doublons, environ 2/3 des éléments seront éliminés à chaque récursivité. Chaque niveau de récursivité est O (n) où petit n est la quantité d'éléments restants. Le seul problème est qu'en pratique, c'est plus lent qu'un tri rapide quand il y a peu de doublons, c'est-à-dire beaucoup de collisions. Cependant, lorsqu'il y a d'énormes quantités de doublons, c'est incroyablement rapide.
Edit: Dans les implémentations actuelles de D, hash_t est de 32 bits. Tout dans cet algorithme suppose qu'il y aura très peu de collisions de hachage, voire aucune, dans un espace 32 bits complet. Les collisions peuvent cependant se produire fréquemment dans l'espace du module. Cependant, cette hypothèse sera vraisemblablement vraie pour tout ensemble de données de taille raisonnable. Si la clé est inférieure ou égale à 32 bits, il peut s'agir de son propre hachage, ce qui signifie qu'une collision dans un espace complet de 32 bits est impossible. S'il est plus grand, vous ne pouvez tout simplement pas en insérer suffisamment dans l'espace d'adressage mémoire 32 bits pour que cela pose un problème. Je suppose que hash_t sera augmenté à 64 bits dans les implémentations 64 bits de D, où les ensembles de données peuvent être plus volumineux. De plus, si cela s'avérait un problème, on pourrait changer la fonction de hachage à chaque niveau de récursivité.
Voici une implémentation dans le langage de programmation D:
la source
Une implémentation plus efficace
Dans cette implémentation, il n'est pas nécessaire de trier le tableau. De plus, si un élément dupliqué est trouvé, il n'est pas nécessaire de décaler tous les éléments après cela d'une position.
La sortie de ce code est array [] avec la taille NewLength
Ici, nous partons du 2ème élément du tableau et le comparons avec tous les éléments du tableau jusqu'à ce tableau. Nous tenons une variable d'index supplémentaire 'NewLength' pour modifier le tableau d'entrée. La variable NewLength est initialisée à 0.
L'élément du tableau [1] sera comparé au tableau [0]. S'ils sont différents, la valeur du tableau [NewLength] sera modifiée avec le tableau [1] et l'incrémentation NewLength. S'ils sont identiques, NewLength ne sera pas modifié.
Donc, si nous avons un tableau [1 2 1 3 1], alors
Dans le premier passage de la boucle 'j', le tableau [1] (2) sera comparé à array0, puis 2 sera écrit dans le tableau [NewLength] = array [1] donc le tableau sera [1 2] puisque NewLength = 2
Dans le deuxième passage de la boucle «j», le tableau [2] (1) sera comparé à tableau0 et tableau1. Ici, puisque array [2] (1) et array0 sont identiques, la boucle sera interrompue ici. donc le tableau sera [1 2] puisque NewLength = 2
etc
la source
Si vous recherchez la notation O supérieure, alors trier le tableau avec un tri O (n log n) puis effectuer un parcours O (n) peut être la meilleure route. Sans tri, vous regardez O (n ^ 2).
Edit: si vous ne faites que des entiers, vous pouvez également faire un tri par base pour obtenir O (n).
la source
1. Utilisation de l'espace supplémentaire O (1), en temps O (n log n)
Ceci est possible, par exemple:
Je crois que le partenaire d'ejel a raison de dire que la meilleure façon de procéder serait une sorte de fusion sur place avec une étape de fusion simplifiée, et c'est probablement l'intention de la question, si vous étiez par exemple. écrire une nouvelle fonction de bibliothèque pour le faire aussi efficacement que possible sans possibilité d'améliorer les entrées, et dans certains cas, il serait utile de le faire sans table de hachage, selon les types d'entrées. Mais je n'ai pas vraiment vérifié cela.
2. Utilisation d'espace supplémentaire O (lots), en temps O (n)
Cela ne fonctionne que si plusieurs hypothèses discutables sont valables:
C'est une mauvaise réponse, mais si vous avez BEAUCOUP d'éléments d'entrée, mais ce sont tous des entiers de 8 bits (ou peut-être même des entiers de 16 bits), cela pourrait être le meilleur moyen.
3. O (peu) -espace supplémentaire, O (n) -ish temps
Comme n ° 2, mais utilisez une table de hachage.
4. La voie claire
Si le nombre d'éléments est petit, l'écriture d'un algorithme approprié n'est pas utile si un autre code est plus rapide à écrire et plus rapide à lire.
Par exemple. Parcourez le tableau pour chaque élément unique (c'est-à-dire le premier élément, le deuxième élément (les doublons du premier ayant été supprimés), etc.) en supprimant tous les éléments identiques. O (1) espace supplémentaire, O (n ^ 2) temps.
Par exemple. Utilisez les fonctions de bibliothèque qui font cela. l'efficacité dépend de ce que vous avez facilement disponible.
la source
Eh bien, sa mise en œuvre de base est assez simple. Parcourez tous les éléments, vérifiez s'il y a des doublons dans les autres et déplacez le reste sur eux.
C'est terriblement inefficace et vous pourriez l'accélérer par un tableau d'aide pour la sortie ou le tri / les arbres binaires, mais cela ne semble pas être autorisé.
la source
Si vous êtes autorisé à utiliser C ++, un appel à
std::sort
suivi d'un appel àstd::unique
vous donnera la réponse. La complexité temporelle est O (N log N) pour le tri et O (N) pour le parcours unique.Et si C ++ est hors de la table, il n'y a rien qui empêche ces mêmes algorithmes d'être écrits en C.
la source
Vous pouvez le faire en un seul parcours, si vous êtes prêt à sacrifier la mémoire. Vous pouvez simplement compter si vous avez vu un entier ou non dans un tableau de hachage / associatif. Si vous avez déjà vu un nombre, supprimez-le au fur et à mesure, ou mieux encore, déplacez les numéros que vous n'avez pas vus dans un nouveau tableau, en évitant tout déplacement dans le tableau d'origine.
En Perl:
la source
La valeur de retour de la fonction doit être le nombre d'éléments uniques et ils sont tous stockés au début du tableau. Sans ces informations supplémentaires, vous ne saurez même pas s'il y a eu des doublons.
Chaque itération de la boucle externe traite un élément du tableau. S'il est unique, il reste au début du tableau et s'il s'agit d'un doublon, il est écrasé par le dernier élément non traité du tableau. Cette solution s'exécute en temps O (n ^ 2).
la source
Voici une version Java.
la source
Voici ma solution.
la source
Un tableau doit évidemment être "parcouru" de droite à gauche pour éviter une copie inutile des valeurs dans les deux sens.
Si vous avez une mémoire illimitée, vous pouvez allouer un tableau de bits pour les
sizeof(type-of-element-in-array) / 8
octets pour que chaque bit indique si vous avez déjà rencontré la valeur correspondante ou non.Si vous ne le faites pas, je ne peux rien penser de mieux que de parcourir un tableau et de comparer chaque valeur avec les valeurs qui la suivent, puis si un doublon est trouvé, supprimez complètement ces valeurs. C'est quelque part près de O (n ^ 2) (ou O ((n ^ 2-n) / 2) ).
IBM a un article sur un sujet assez proche.
la source
Voyons voir:
la source
Cela peut être fait en une seule passe avec un algorithme O (N log N) et sans stockage supplémentaire.
Passez de l'élément
a[1]
àa[N]
. A chaque étapei
, l' ensemble des éléments à la gauche dea[i]
comprendre un tas d'éléments triés àa[0]
traversa[j]
. Pendant ce temps, un deuxième indexj
, initialement 0, garde une trace de la taille du tas.Examiner
a[i]
et l' insérer dans le tas, qui occupe maintenant les élémentsa[0]
àa[j+1]
. Lorsque l'élément est inséré, si un élément dupliquéa[k]
ayant la même valeur est rencontré, ne l'insérez pasa[i]
dans le tas (c'est-à-dire, le rejetez); sinon, insérez-le dans le tas, qui augmente maintenant d'un élément et comprend maintenanta[0]
toa[j+1]
, et incrémentj
.Continuez de cette manière, en incrémentant
i
jusqu'à ce que tous les éléments du tableau aient été examinés et insérés dans le tas, qui finit par occupera[0]
àa[j]
.j
est l'index du dernier élément du tas, et le tas contient uniquement des valeurs d'élément uniques.En regardant l'exemple, ce n'est pas exactement ce qui a été demandé car le tableau résultant préserve l'ordre des éléments d'origine. Mais si cette exigence est assouplie, l'algorithme ci-dessus devrait faire l'affaire.
la source
En Java, je le résoudrais comme ça. Je ne sais pas comment écrire cela en C.
la source
Que diriez-vous de ce qui suit?
J'essaie de déclarer un tableau temporaire et d'y mettre les éléments avant de tout copier dans le tableau d'origine.
la source
Après avoir examiné le problème, voici ma manière Delphi, qui peut aider
la source
L'exemple suivant devrait résoudre votre problème:
la source
la source
C'est la solution naïve (N * (N-1) / 2). Il utilise un espace supplémentaire constant et maintient l'ordre d'origine. Elle est similaire à la solution de @Byju, mais n'utilise aucun
if(){}
bloc. Cela évite également de copier un élément sur lui-même.la source
Cela peut être fait en une seule passe, en temps O (N) dans le nombre d'entiers dans la liste d'entrée, et en stockage O (N) dans le nombre d'entiers uniques.
Parcourez la liste de l'avant vers l'arrière, avec deux pointeurs "dst" et "src" initialisés sur le premier élément. Commencez avec une table de hachage vide des "entiers vus". Si l'entier à src n'est pas présent dans le hachage, écrivez-le dans l'emplacement à dst et incrémentez dst. Ajoutez l'entier en src au hachage, puis incrémentez src. Répétez jusqu'à ce que src passe la fin de la liste d'entrée.
la source
Insérez tous les éléments dans un
binary tree the disregards duplicates
-O(nlog(n))
. Puis extrayez-les tous dans le tableau en effectuant un parcours -O(n)
. Je suppose que vous n'avez pas besoin de conserver l'ordre.la source
Utilisez un filtre de floraison pour le hachage. Cela réduira considérablement la charge mémoire.
la source
Dans JAVA,
sortie: {1, 2, 3, 4, 6, 7, 8, 9, 10}
j'espère que cela aidera
la source
arrayInteger = {100,10,1};
Créez un
BinarySearchTree
qui a une complexité O (n).la source
Tout d'abord, vous devez créer un tableau
check[n]
où n est le nombre d'éléments du tableau que vous voulez rendre sans duplication et définir la valeur de chaque élément (du tableau de contrôle) égale à 1. En utilisant une boucle for parcourez le tableau avec le duplique, dites que son nom estarr
, et dans la boucle for, écrivez ceci:Avec cela, vous définissez chaque doublon égal à zéro. Il ne reste donc plus qu'à parcourir le
arr
tableau et à imprimer tout ce qui n'est pas égal à zéro. L'ordre reste et cela prend un temps linéaire (3 * n).la source
Étant donné un tableau de n éléments, écrivez un algorithme pour supprimer tous les doublons du tableau dans le temps O (nlogn)
Dans d'autres éléments, il est conservé dans le tableau de sortie à l'aide de la «clé». Considérez que la clé est de longueur O (n), le temps nécessaire pour effectuer le tri sur la clé et la valeur est O (nlogn). Ainsi, le temps nécessaire pour supprimer tous les doublons du tableau est O (nlogn).
la source
helper data structure (e.g. hashtable) should not be used
?c'est ce que j'ai, bien que cela égare l'ordre dans lequel nous pouvons trier par ordre croissant ou décroissant pour le réparer.
la source
Ce serait cool si vous aviez une bonne DataStructure qui pourrait rapidement dire si elle contient un entier. Peut-être un arbre quelconque.
la source