Supposons que le tableau donné soit A avec une longueur N. Supposons que dans le tableau donné, l'unique emplacement vide soit rempli de 0.
Nous pouvons trouver la solution de ce problème en utilisant de nombreuses méthodes, y compris l'algorithme utilisé dans Counting sort
. Mais, en termes d'utilisation efficace du temps et de l'espace, nous avons deux algorithmes. L'un utilise principalement la sommation, la soustraction et la multiplication. L'autre utilise la méthode XOR. Mathématiquement, les deux méthodes fonctionnent bien. Mais d'un point de vue programmatique, nous devons évaluer tous les algorithmes à l'aide de mesures principales telles que
- Limites (par exemple, les valeurs d'entrée sont importantes)
A[1...N]
) et/ou le nombre de valeurs d'entrée est important( N
))
- Nombre de contrôles d'état concernés
- Nombre et type d'opérations mathématiques impliquées
etc. Ceci est dû aux limitations de temps et/ou de matériel (limitation des ressources matérielles) et/ou de logiciel (limitation du système d'exploitation, limitation du langage de programmation, etc. Dressons une liste et évaluons les avantages et les inconvénients de chacun d'entre eux.
Algorithme 1 :
Dans l'algorithme 1, nous avons 3 implémentations.
-
Calculez la somme totale de tous les nombres (y compris le nombre manquant inconnu) en utilisant la formule mathématique( 1+2+3+...+N=(N(N+1))/2
). Ici, N=100
. Calculez la somme totale de tous les nombres donnés. En soustrayant le deuxième résultat du premier, on obtient le nombre manquant.
Missing Number = (N(N+1))/2) - (A[1]+A[2]+...+A[100])
-
Calculez la somme totale de tous les nombres (y compris le nombre manquant inconnu) en utilisant la formule mathématique( 1+2+3+...+N=(N(N+1))/2
). Ici, N=100
. De ce résultat, soustrayez chaque nombre donné donne le nombre manquant.
Missing Number = (N(N+1))/2)-A[1]-A[2]-...-A[100]
( Note:
Même si la formule de la deuxième implémentation est dérivée de la première, d'un point de vue mathématique, les deux sont identiques. Mais du point de vue de la programmation, les deux sont différentes car la première formule est plus sujette au débordement de bits que la seconde (si les nombres donnés sont assez grands). Même si l'addition est plus rapide que la soustraction, la deuxième implémentation réduit le risque de débordement de bits causé par l'addition de grandes valeurs (il n'est pas complètement éliminé, car il y a toujours une très petite chance puisque ( N+1
) est présent dans la formule). Mais les deux sont également sujets à un débordement de bits par multiplication. La limitation est que les deux implémentations donnent un résultat correct seulement si N(N+1)<=MAXIMUM_NUMBER_VALUE
. Pour la première implémentation, la limitation supplémentaire est qu'elle donne un résultat correct seulement si Sum of all given numbers<=MAXIMUM_NUMBER_VALUE
.)
-
Calculez la somme totale de tous les nombres (y compris le nombre manquant inconnu) et soustrayez chaque nombre donné dans la même boucle en parallèle. Cela élimine le risque de débordement de bits par la multiplication mais risque de débordement de bits par l'addition et la soustraction.
//ALGORITHM missingNumber = 0; foreach(index from 1 to N) { missingNumber = missingNumber + index; //Since, the empty slot is filled with 0, //this extra condition which is executed for N times is not required. //But for the sake of understanding of algorithm purpose lets put it. if (inputArray[index] != 0) missingNumber = missingNumber - inputArray[index]; }
Dans un langage de programmation (comme C, C++, Java, etc.), si le nombre de bits représentant un type de données entières est limité, toutes les implémentations ci-dessus sont sujettes à un débordement de bits en raison de la sommation, de la soustraction et de la multiplication, ce qui donne un résultat erroné en cas de grandes valeurs d'entrée. A[1...N]
) et/ou un grand nombre de valeurs d'entrée ( N
).
Algorithme 2 :
Nous pouvons utiliser la propriété XOR pour résoudre ce problème sans nous soucier du problème de débordement de bits. De plus, XOR est à la fois plus sûr et plus rapide que la sommation. Nous connaissons la propriété du XOR selon laquelle le XOR de deux mêmes nombres est égal à 0( A XOR A = 0
). Si nous calculons le XOR de tous les nombres de 1 à N (y compris le nombre manquant inconnu) et qu'avec ce résultat, nous XORons tous les nombres donnés, les nombres communs sont annulés (puisque A XOR A=0
) et à la fin nous obtenons le numéro manquant. Si nous n'avons pas de problème de débordement de bits, nous pouvons utiliser les algorithmes basés sur la sommation et le XOR pour obtenir la solution. Mais l'algorithme qui utilise XOR est à la fois plus sûr et plus rapide que l'algorithme qui utilise la sommation, la soustraction et la multiplication. Et nous pouvons éviter les soucis supplémentaires causés par la sommation, la soustraction et la multiplication.
Dans toutes les implémentations de l'algorithme 1, nous pouvons utiliser XOR au lieu de l'addition et de la soustraction.
Supposons, XOR(1...N) = XOR of all numbers from 1 to N
Mise en œuvre 1 => Missing Number = XOR(1...N) XOR (A[1] XOR A[2] XOR...XOR A[100])
Mise en œuvre 2 => Missing Number = XOR(1...N) XOR A[1] XOR A[2] XOR...XOR A[100]
Mise en œuvre 3 =>
//ALGORITHM
missingNumber = 0;
foreach(index from 1 to N)
{
missingNumber = missingNumber XOR index;
//Since, the empty slot is filled with 0,
//this extra condition which is executed for N times is not required.
//But for the sake of understanding of algorithm purpose lets put it.
if (inputArray[index] != 0)
missingNumber = missingNumber XOR inputArray[index];
}
Les trois implémentations de l'algorithme 2 fonctionneront bien (d'un point de vue programmatique également). Une optimisation est, comme pour
1+2+....+N = (N(N+1))/2
Nous avons,
1 XOR 2 XOR .... XOR N = {N if REMAINDER(N/4)=0, 1 if REMAINDER(N/4)=1, N+1 if REMAINDER(N/4)=2, 0 if REMAINDER(N/4)=3}
Nous pouvons le prouver par induction mathématique. Ainsi, au lieu de calculer la valeur de XOR(1...N) en XORant tous les nombres de 1 à N, nous pouvons utiliser cette formule pour réduire le nombre d'opérations XOR.
De même, le calcul de XOR(1...N) à l'aide de la formule ci-dessus a deux implémentations. En termes d'implémentation, le calcul de
// Thanks to https://a3nm.net/blog/xor.html for this implementation
xor = (n>>1)&1 ^ (((n&1)>0)?1:n)
est plus rapide que de calculer
xor = (n % 4 == 0) ? n : (n % 4 == 1) ? 1 : (n % 4 == 2) ? n + 1 : 0;
Ainsi, le code Java optimisé est,
long n = 100;
long a[] = new long[n];
//XOR of all numbers from 1 to n
// n%4 == 0 ---> n
// n%4 == 1 ---> 1
// n%4 == 2 ---> n + 1
// n%4 == 3 ---> 0
//Slower way of implementing the formula
// long xor = (n % 4 == 0) ? n : (n % 4 == 1) ? 1 : (n % 4 == 2) ? n + 1 : 0;
//Faster way of implementing the formula
// long xor = (n>>1)&1 ^ (((n&1)>0)?1:n);
long xor = (n>>1)&1 ^ (((n&1)>0)?1:n);
for (long i = 0; i < n; i++)
{
xor = xor ^ a[i];
}
//Missing number
System.out.println(xor);
3 votes
En fait, je connaissais une solution - trouver la somme des nombres de 1 à 100 et la soustraire de la somme des nombres dans le tableau pour obtenir le nombre manquant.je suis intéressé de voir s'il peut y avoir d'autres solutions intéressantes.
2 votes
Quelle est la valeur de "empty" ? 0 ? -1 ?
3 votes
On m'a posé cette question lors d'un entretien
0 votes
Je pense que la réponse de Sayro est la meilleure dans cette condition.
2 votes
Comment faire si vos entiers ne commencent pas à 1 ? Par exemple { 15, 16, 17, 19, 20} ?
0 votes
@CBC_NS, dans ce cas, il suffit de calculer d'abord la somme de 1 à 20 puis de soustraire la somme de 1 à 14 en utilisant la même formule (voir la réponse) pour obtenir la somme de la somme non manquante.
0 votes
Comme @CBC_NS l'a dit, vous pouvez soustraire la somme de tous les nombres inférieurs à la limite inférieure dans le tableau. De cette façon, vous n'aurez plus que la somme de l'intervalle que nous avons considéré. L'implémentation suivante est présentée dans cet article davidsekar.com/algorithmes/missing-number-in-an-integer-sequence