Il existe un tableau de taille n (les nombres sont compris entre 0 et n - 3) et seuls 2 nombres sont répétés. Les éléments sont placés au hasard dans le tableau.
Par exemple. dans {2, 3, 6, 1, 5, 4, 0, 3, 5} n = 9 et les nombres répétés sont 3 et 5.
Quelle est la meilleure façon de trouver les nombres répétés?
P.S. [Vous ne devriez pas utiliser le tri]
Il existe une solution O(n) si vous connaissez le domaine de saisie possible. Par exemple, si votre tableau d'entrée contient des nombres compris entre 0 et 100, considérez le code suivant.
bool flags[100];
for(int i = 0; i < 100; i++)
flags[i] = false;
for(int i = 0; i < input_size; i++)
if(flags[input_array[i]])
return input_array[i];
else
flags[input_array[i]] = true;
Bien sûr, il y a la mémoire supplémentaire, mais c'est le plus rapide.
OK, semble que je ne peux tout simplement pas me reposer :)
int A[N] = {...};
int signed_1(n) { return n%2<1 ? +n : -n; } // 0,-1,+2,-3,+4,-5,+6,-7,...
int signed_2(n) { return n%4<2 ? +n : -n; } // 0,+1,-2,-3,+4,+5,-6,-7,...
long S1 = 0; // or int64, or long long, or some user-defined class
long S2 = 0; // so that it has enough bits to contain sum without overflow
for (int i=0; i<N-2; ++i)
{
S1 += signed_1(A[i]) - signed_1(i);
S2 += signed_2(A[i]) - signed_2(i);
}
for (int i=N-2; i<N; ++i)
{
S1 += signed_1(A[i]);
S2 += signed_2(A[i]);
}
S1 = abs(S1);
S2 = abs(S2);
assert(S1 != S2); // this algorithm fails in this case
p = (S1+S2)/2;
q = abs(S1-S2)/2;
Une somme (S1 ou S2) contient p et q avec le même signe, l'autre somme - avec des signes opposés, tous les autres membres sont éliminés.
S1 et S2 doivent avoir assez de bits pour recevoir des sommes, l’algorithme ne signifie pas débordement à cause de abs ().
si abs (S1) == abs (S2), l'algorithme échoue, bien que cette valeur reste la différence entre p et q (c'est-à-dire abs (p - q) == abs (S1)).
Je doute que quelqu'un rencontre un tel problème sur le terrain;)
.__ et je suppose que je connais les attentes de l'enseignant:
Prenons le tableau {0,1,2, ..., n-2, n-1},
Le donné peut être produit en remplaçant les deux derniers éléments n-2 et n-1 par inconnus p et q (ordre inférieur)
alors, la somme des éléments sera (n-1) n/2+ p + q - (n-2) - (n-1)
la somme des carrés (n-1) n (2n-1)/6+ p ^ 2 + q ^ 2 - (n-2) ^ 2 - (n-1) ^ 2
Reste simple maths:
(1) p+q = S1
(2) p^2+q^2 = S2
Vous ne pourrez certainement pas le résoudre car les cours de mathématiques enseignent la résolution d’équations carrées.
Tout d’abord, tout calculer modulo 2 ^ 32, c’est-à-dire permettre le débordement.
Ensuite, vérifiez les paires {p, q}: {0, S1}, {1, S1-1} ... contre l'expression (2) pour trouver les candidats (il peut y en avoir plus de 2 en raison de modulo et de la quadrature )
Et enfin, vérifiez les candidats trouvés s’ils sont réellement présents dans le tableau deux fois.
Vous savez que votre tableau contient tous les nombres de 0 à n-3 et les deux nombres qui se répètent (p & q). Pour plus de simplicité, ignorons le cas 0 pour le moment.
Vous pouvez calculer la somme et le produit sur le tableau, ce qui donne:
1 + 2 + ... + n-3 + p + q = p + q + (n-3)(n-2)/2
Donc, si vous soustrayez (n-3) (n-2)/2 de la somme de tout le tableau, vous obtenez
sum(Array) - (n-3)(n-2)/2 = x = p + q
Maintenant, faites la même chose pour le produit:
1 * 2 * ... * n - 3 * p * q = (n - 3)! * p * q
prod(Array) / (n - 3)! = y = p * q
Vous avez maintenant ces termes:
x = p + q
y = p * q
=> y(p + q) = x(p * q)
Si vous transformez ce terme, vous devriez pouvoir calculer p et q
Insérez chaque élément dans un ensemble/hashtable, en vérifiant d’abord s'il en contient déjà.
Vous pourrez peut-être tirer parti du fait que somme (tableau) = (n-2) * (n-3)/2 + deux nombres manquants.
Edit: Comme d’autres l’ont noté, en combinaison avec la somme des carrés, vous pouvez l’utiliser, j’étais un peu lent à le comprendre.
Vérifiez ce vieux mais bon article sur le sujet:
Quelques réponses à la question: Algorithme pour déterminer si le tableau contient n… n + m? contient en tant que sous-problème des solutions que vous pouvez adopter en fonction de vos besoins.
Par exemple, voici une partie pertinente de ma réponse :
bool has_duplicates(int* a, int m, int n)
{
/** O(m) in time, O(1) in space (for 'typeof(m) == typeof(*a) == int')
Whether a[] array has duplicates.
precondition: all values are in [n, n+m) range.
feature: It marks visited items using a sign bit.
*/
assert((INT_MIN - (INT_MIN - 1)) == 1); // check n == INT_MIN
for (int *p = a; p != &a[m]; ++p) {
*p -= (n - 1); // [n, n+m) -> [1, m+1)
assert(*p > 0);
}
// determine: are there duplicates
bool has_dups = false;
for (int i = 0; i < m; ++i) {
const int j = abs(a[i]) - 1;
assert(j >= 0);
assert(j < m);
if (a[j] > 0)
a[j] *= -1; // mark
else { // already seen
has_dups = true;
break;
}
}
// restore the array
for (int *p = a; p != &a[m]; ++p) {
if (*p < 0)
*p *= -1; // unmark
// [1, m+1) -> [n, n+m)
*p += (n - 1);
}
return has_dups;
}
Le programme laisse le tableau inchangé (le tableau doit être accessible en écriture mais ses valeurs sont restaurées à la sortie).
Cela fonctionne pour les tailles de tableau jusqu'à INT_MAX
(sur les systèmes 64 bits, il s'agit de 9223372036854775807
).
supposons qu'un tableau est a [0], a [1], a [2] ..... a [n-1] sumA = a [0] + a [1 ] + .... + a [n-1] sumASquare = a [0] * a [0] + a [1] * a [1] + a [2] * a [2] + .. .. + a [n] * a [n] sumFirstN = (N * (N + 1))/2 où N = n-3 so sumFirstN = (n-3) (n -2)/2 De même SumFirstNSquare = N * (N + 1) * (2 * N + 1)/6 = (n-3) (n-2) (2n -5)/6 Supposons que les éléments répétés soient = X et Y Donc X + Y = sumA - sumFirstN; X * X + Y * Y = sumASquare - sumFirstNSquare ; Ainsi, en résolvant ce quadratique, nous pouvons obtenir les valeurs de X et Y . Complexité temporelle = O (n) Complexité spatiale = O (1)
Je sais que la question est très ancienne, mais je l'ai soudainement posée et je pense avoir une réponse intéressante à cette question ..__ Nous savons qu'il s'agit d'un casse-tête et d'une solution triviale (par exemple, HashMap, Sort, etc.), peu importe leur qualité serait ennuyeux.
Comme les nombres sont des nombres entiers, ils ont une taille de bits constante (c'est-à-dire 32). Supposons que nous travaillons actuellement avec des entiers 4 bits. Nous cherchonsAetBqui sont les numéros en double.
Nous avons besoin de 4 seaux, chacun pour un bit. Chaque compartiment contient des nombres dont le bit spécifique est 1. Par exemple, le compartiment 1 obtient 2, 3, 4, 7, ...:
Bucket 0 : Sum ( x where: x & 2 power 0 == 0 )
...
Bucket i : Sum ( x where: x & 2 power i == 0 )
Nous savons quelle serait la somme de chaque panier s'il n'y avait pas de doublon. Je considère cela comme une connaissance préalable.
Une fois que les compartiments ci-dessus sont générés, nombre d'entre eux auront des valeurs plus élevées que prévu. En construisant le nombre à partir de seaux nous aurons (A OR B pour votre information).
Nous pouvons calculer (A XOR B) comme suit:
A XOR B = Array[i] XOR Array[i-1] XOR ... 0, XOR n-3 XOR n-2 ... XOR 0
Revenons maintenant aux catégories, nous savons exactement quelles catégories ont nos numéros et lesquelles n’en ont qu’un (de la partie XOR).
Pour les compartiments n'ayant qu'un seul numéro, nous pouvons extraire le nombre num = (somme - somme attendue du compartiment). Cependant, nous ne devrions être bons que si nous pouvons trouver l'un des numéros en double, donc si nous avons au moins un bit dans A XOR B, nous avons la réponse.
Mais que se passe-t-il si A XOR B est égal à zéro? Ce cas n’est possible que si les deux numéros en double sont identiques, ce qui correspond à la réponse de A OR B.
répondez à 18 .. vous prenez un tableau de 9 et les éléments commencent à 0..so max ele sera 6 dans votre tableau. Prendre la somme des éléments de 0 à 6 et la somme des éléments du tableau. calcule leur différence (disons d). C'est p + q. Maintenant, prenez XOR des éléments de 0 à 6 (disons x1). Maintenant, prenons XOR des éléments du tableau (disons x2). x2 est XOR de tous les éléments de 0 à 6 sauf deux éléments répétés car ils s'annulent l'un l'autre. maintenant pour i = 0 à 6, pour chaque ele de tableau, disons que p est cet ele a [i] afin que vous puissiez calculer q en soustrayant cet ele du d. faites XOR de p et q et XOR avec x2 et vérifiez si x1 == x2. de même, pour tous les éléments, vous obtiendrez les éléments pour lesquels cette condition sera vraie et vous le ferez dans O (n). Continuez à coder!
Puisqu'une plage est spécifiée, vous pouvez effectuer un tri de base. Cela trierait votre tableau dans O (n). La recherche de doublons dans un tableau trié est alors O (n)
Vous pouvez utiliser une boucle imbriquée simple
int[] numArray = new int[] { 1, 2, 3, 4, 5, 7, 8, 3, 7 };
for (int i = 0; i < numArray.Length; i++)
{
for (int j = i + 1; j < numArray.Length; j++)
{
if (numArray[i] == numArray[j])
{
//DO SOMETHING
}
}
*OR vous pouvez filtrer le tableau et utiliser la fonction récursive si vous souhaitez obtenir le nombre d'occurrences *
int[] array = { 1, 2, 3, 4, 5, 4, 4, 1, 8, 9, 23, 4, 6, 8, 9, 1,4 };
int[] myNewArray = null;
int a = 1;
void GetDuplicates(int[] array)
for (int i = 0; i < array.Length; i++)
{
for (int j = i + 1; j < array.Length; j++)
{
if (array[i] == array[j])
{
a += 1;
}
}
Console.WriteLine(" {0} occurred {1} time/s", array[i], a);
IEnumerable<int> num = from n in array where n != array[i] select n;
myNewArray = null;
a = 1;
myNewArray = num.ToArray() ;
break;
}
GetDuplicates(myNewArray);
vérifier cela ... O (n) temps et O(1) complexité de l'espace
for(i=0;i< n;i++)
xor=xor^arr[i]
for(i=1;i<=n-3;i++)
xor=xor^i;
Donc, dans l'exemple donné, vous obtiendrez le xor de 3 et 5
xor=xor & -xor //Isolate the last digit
for(i = 0; i < n; i++)
{
if(arr[i] & xor)
x = x ^ arr[i];
else
y = y ^ arr[i];
}
for(i = 1; i <= n-3; i++)
{
if(i & xor)
x = x ^ i;
else
y = y ^ i;
}
x et y sont tes réponses
Trier la matrice semble être la meilleure solution. Un simple tri rendrait alors la recherche triviale et prendrait beaucoup moins de temps/espace.
Sinon, si vous connaissez le domaine des nombres, créez un tableau contenant autant de compartiments et incrémentez-les au fur et à mesure de votre progression dans le tableau. quelque chose comme ça:
int count [10];
for (int i = 0; i < arraylen; i++) {
count[array[i]]++;
}
Ensuite, il suffit de rechercher dans votre tableau les nombres supérieurs à 1. Il s’agit des éléments avec des doublons. Ne nécessite qu'un seul passage sur le tableau d'origine et un autre sur le tableau count.
Voici l'implémentation en Python de la réponse de @ eugensk00 (une de ses révisions) qui n'utilise pas l'arithmétique modulaire. C'est un algorithme single-pass, O(log(n)) dans l'espace. Si des entiers à largeur fixe (par exemple 32 bits) sont utilisés, il ne nécessite que deux nombres à largeur fixe (par exemple pour 32 bits: un nombre 64 bits et un nombre 128 bits). Il peut gérer des séquences entières arbitraires de grande taille (il lit un entier à la fois, donc une séquence entière ne nécessite pas d'être en mémoire).
def two_repeated(iterable):
s1, s2 = 0, 0
for i, j in enumerate(iterable):
s1 += j - i # number_of_digits(s1) ~ 2 * number_of_digits(i)
s2 += j*j - i*i # number_of_digits(s2) ~ 4 * number_of_digits(i)
s1 += (i - 1) + i
s2 += (i - 1)**2 + i**2
p = (s1 - int((2*s2 - s1**2)**.5)) // 2
# `Decimal().sqrt()` could replace `int()**.5` for really large integers
# or any function to compute integer square root
return p, s1 - p
Exemple:
>>> two_repeated([2, 3, 6, 1, 5, 4, 0, 3, 5])
(3, 5)
Une version plus détaillée du code ci-dessus suit avec une explication:
def two_repeated_seq(arr):
"""Return the only two duplicates from `arr`.
>>> two_repeated_seq([2, 3, 6, 1, 5, 4, 0, 3, 5])
(3, 5)
"""
n = len(arr)
assert all(0 <= i < n - 2 for i in arr) # all in range [0, n-2)
assert len(set(arr)) == (n - 2) # number of unique items
s1 = (n-2) + (n-1) # s1 and s2 have ~ 2*(k+1) and 4*(k+1) digits
s2 = (n-2)**2 + (n-1)**2 # where k is a number of digits in `max(arr)`
for i, j in enumerate(arr):
s1 += j - i
s2 += j*j - i*i
"""
s1 = (n-2) + (n-1) + sum(arr) - sum(range(n))
= sum(arr) - sum(range(n-2))
= sum(range(n-2)) + p + q - sum(range(n-2))
= p + q
"""
assert s1 == (sum(arr) - sum(range(n-2)))
"""
s2 = (n-2)**2 + (n-1)**2 + sum(i*i for i in arr) - sum(i*i for i in range(n))
= sum(i*i for i in arr) - sum(i*i for i in range(n-2))
= p*p + q*q
"""
assert s2 == (sum(i*i for i in arr) - sum(i*i for i in range(n-2)))
"""
s1 = p+q
-> s1**2 = (p+q)**2
-> s1**2 = p*p + 2*p*q + q*q
-> s1**2 - (p*p + q*q) = 2*p*q
s2 = p*p + q*q
-> p*q = (s1**2 - s2)/2
Let C = p*q = (s1**2 - s2)/2 and B = p+q = s1 then from Viete theorem follows
that p and q are roots of x**2 - B*x + C = 0
-> p = (B + sqrtD) / 2
-> q = (B - sqrtD) / 2
where sqrtD = sqrt(B**2 - 4*C)
-> p = (s1 + sqrt(2*s2 - s1**2))/2
"""
sqrtD = (2*s2 - s1**2)**.5
assert int(sqrtD)**2 == (2*s2 - s1**2) # perfect square
sqrtD = int(sqrtD)
assert (s1 - sqrtD) % 2 == 0 # even
p = (s1 - sqrtD) // 2
q = s1 - p
assert q == ((s1 + sqrtD) // 2)
assert sqrtD == (q - p)
return p, q
REMARQUE: le calcul de la racine carrée entière d'un nombre (~ N ** 4) rend l'algorithme ci-dessus non linéaire.
En c:
int arr[] = {2, 3, 6, 1, 5, 4, 0, 3, 5};
int num = 0, i;
for (i=0; i < 8; i++)
num = num ^ arr[i] ^i;
Depuis x^x=0
, les nombres répétés un nombre impair de fois sont neutralisés. Appelons les numéros uniques a et b. Il nous reste a^b
. Nous connaissons a^b != 0
, depuis a != b
. Choisissez un bit de a^b
et utilisez-le comme masque ie.choose x comme puissance 2, de sorte que x & (a^b)
soit différent de zéro.
Maintenant divisez la liste en deux sous-listes - une sous-liste contient tous les nombres y avec y&x == 0
, et le reste va dans l’autre sous-liste En passant, nous avons choisi x, nous savons que les paires de a et b sont dans des compartiments différents. Nous pouvons donc maintenant appliquer la même méthode utilisée ci-dessus à chaque compartiment de manière indépendante et découvrir ce que sont a et b.
Que dis-tu de ça:
for (i=0; i<n-1; i++) {
for (j=i+1; j<n; j++) {
if (a[i] == a[j]) {
printf("%d appears more than once\n",a[i]);
break;
}
}
}
Bien sûr, ce n’est pas le plus rapide, mais c’est simple, facile à comprendre et ne nécessite pas de mémoire supplémentaire. Si n est un petit nombre comme 9 ou 100, alors il se peut que ce soit le "meilleur". (Par exemple, "Meilleur" pourrait signifier différentes choses: plus rapide à exécuter, plus petite empreinte mémoire, plus maintenable, moins coûteux à développer, etc.
J'ai écrit un petit programme qui détecte le nombre d'éléments non répétés. Lisez-le moi, votre opinion est la suivante: pour le moment, je suppose qu'un nombre pair d'éléments est pair mais peut facilement être étendu pour des nombres impairs également.
Donc, mon idée est d’abord de trier les nombres, puis d’appliquer mon algorithme. Un tri rapide peut être utilisé pour trier ces éléments.
Prenons un tableau d'entrée comme ci-dessous
int arr[] = {1,1,2,10,3,3,4,5,5,6,6};
les chiffres 2,10 et 4 ne sont pas répétés, mais ils sont triés. Sinon, utilisez le tri rapide pour le trier.
Permet d'appliquer mon programme sur ce
using namespace std;
main()
{
//int arr[] = {2, 9, 6, 1, 1, 4, 2, 3, 5};
int arr[] = {1,1,2,10,3,3,4,5,5,6,6};
int i = 0;
vector<int> vec;
int var = arr[0];
for(i = 1 ; i < sizeof(arr)/sizeof(arr[0]); i += 2)
{
var = var ^ arr[i];
if(var != 0 )
{
//put in vector
var = arr[i-1];
vec.Push_back(var);
i = i-1;
}
var = arr[i+1];
}
for(int i = 0 ; i < vec.size() ; i++)
printf("value not repeated = %d\n",vec[i]);
}
Cela donne la sortie:
value not repeated= 2
value not repeated= 10
value not repeated= 4
C'est simple et très simple, utilisez simplement XOR man.
Voici un algorithme qui utilise les statistiques d'ordre et s'exécute dans O(n)
.
Vous pouvez résoudre ce problème en appelant à plusieurs reprises SELECT
avec la médiane en tant que paramètre.
Vous vous appuyez également sur le fait que, après un appel à SELECT
, , Les éléments inférieurs ou égaux à la médiane sont déplacés à gauche de la médiane.
SELECT
sur A
avec la médiane comme paramètre.floor(n/2)
, les valeurs répétées correspondent à la médiane. Donc, vous continuez avec la moitié droite du tableau.Par exemple:
A={2, 3, 6, 1, 5, 4, 0, 3, 5}
n=9
, la médiane doit être la valeur 4
.SELECT
A={3, 2, 0, 1, <3>, 4, 5, 6, 5}
La valeur médiane étant inférieure à 4
, nous continuons avec la moitié gauche.A={3, 2, 0, 1, 3}
SELECT
A={1, 0, <2>, 3, 3}
alors la médiane devrait être 2
et nous allons donc continuer avec la moitié droite.A={3, 3}
, trouvé.Cet algorithme fonctionne dans O(n+n/2+n/4+...)=O(n)
.
for(i=1;i<=n;i++) {
if(!(arr[i] ^ arr[i+1]))
printf("Found Repeated number %5d",arr[i]);
}
Pour chaque nombre: vérifiez s'il existe dans le reste du tableau.
Sans trier, vous gardez une trace des chiffres que vous avez déjà visités.
dans psuedocode, cela serait essentiellement (ce qui fait que je ne vous donne pas simplement la réponse):
for each number in the list
if number not already in unique numbers list
add it to the unique numbers list
else
return that number as it is a duplicate
end if
end for each
Qu'en est-il de l'utilisation du https://en.wikipedia.org/wiki/HyperLogLog ?
Redis fait http://redis.io/topics/data-types-intro#hyperloglogs
Un HyperLogLog est une structure de données probabiliste utilisée pour compter des choses uniques (on parle techniquement d'estimer la cardinalité d'un ensemble). Généralement, le comptage d’éléments uniques nécessite d’utiliser une quantité de mémoire proportionnelle au nombre d’éléments à compter, car vous devez vous rappeler des éléments que vous avez déjà vus dans le passé pour éviter de les compter plusieurs fois. Cependant, il existe un ensemble d'algorithmes qui échangent de la mémoire contre de la précision: vous vous retrouvez avec une mesure estimée avec une erreur standard, dans le cas de l'implémentation Redis, inférieure à 1%. La magie de cet algorithme est qu'il n'est plus nécessaire d'utiliser une quantité de mémoire proportionnelle au nombre d'éléments comptés, mais que vous pouvez utiliser une quantité de mémoire constante! 12k octets dans le pire des cas, ou beaucoup moins si votre HyperLogLog (nous les appellerons simplement HLL à partir de maintenant) a vu très peu d'éléments.