Existe-t-il une méthode intégrée dans une bibliothèque java qui permet de calculer 'N choisir R' pour tout N, R ?
J'ai remarqué un grand gain de performance en utilisant cette approche (par rapport au calcul récursif).
Existe-t-il une méthode intégrée dans une bibliothèque java qui permet de calculer 'N choisir R' pour tout N, R ?
C'est en fait très facile à calculer N choose K
sans même calculer les factorielles.
Nous savons que la formule pour (N choose K)
est :
N!
--------
(N-K)!K!
Par conséquent, la formule pour (N choose K+1)
est :
N! N! N! N! (N-K)
---------------- = --------------- = -------------------- = -------- x -----
(N-(K+1))!(K+1)! (N-K-1)! (K+1)! (N-K)!/(N-K) K!(K+1) (N-K)!K! (K+1)
C'est-à-dire :
(N choose K+1) = (N choose K) * (N-K)/(K+1)
Nous savons également que (N choose 0)
est :
N!
---- = 1
N!0!
Cela nous donne donc un point de départ facile, et en utilisant la formule ci-dessus, nous pouvons trouver (N choose K)
pour tout K > 0
con K
les multiplications et K
divisions.
En combinant les éléments ci-dessus, nous pouvons facilement générer le triangle de Pascal comme suit :
for (int n = 0; n < 10; n++) {
int nCk = 1;
for (int k = 0; k <= n; k++) {
System.out.print(nCk + " ");
nCk = nCk * (n-k) / (k+1);
}
System.out.println();
}
Cette empreinte :
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
BigInteger
versionEn appliquant la formule pour BigInteger
est simple :
static BigInteger binomial(final int N, final int K) {
BigInteger ret = BigInteger.ONE;
for (int k = 0; k < K; k++) {
ret = ret.multiply(BigInteger.valueOf(N-k))
.divide(BigInteger.valueOf(k+1));
}
return ret;
}
//...
System.out.println(binomial(133, 71));
// prints "555687036928510235891585199545206017600"
Selon Google, 133 choisir 71 = 5,55687037 × 10 38 .
J'ai remarqué un grand gain de performance en utilisant cette approche (par rapport au calcul récursif).
Votre solution pour imprimer le triangle de Pascal ne fonctionne pas pour les grands nombres. Prenons l'exemple de 30.
Une petite note d'implémentation sur votre fonction binomiale : Au lieu d'itérer jusqu'à K, vous pouvez itérer jusqu'à min(N-K, K).
Le module "Math" d'apache-commons prend en charge cette fonction en org.apache.commons.math4.util.CombinatoricsUtils
Aucun des liens précédents ne fonctionne. Lol ! Les responsables d'Apache devraient s'occuper de rediriger leurs anciens liens vers des informations actualisées.
El définition récursive vous donne une fonction de choix assez simple qui fonctionnera bien pour les petites valeurs. Si vous prévoyez d'utiliser cette méthode souvent, ou sur de grandes valeurs, il serait utile de la mémoriser, mais sinon, elle fonctionne très bien.
public static long choose(long total, long choose){
if(total < choose)
return 0;
if(choose == 0 || choose == total)
return 1;
return choose(total-1,choose-1)+choose(total-1,choose);
}
L'amélioration de la durée d'exécution de cette fonction est laissée à l'appréciation de la Commission. exercice pour le lecteur :)
Je déteste pinailler, mais je suis légitimement curieux de savoir pourquoi je viens d'être rétrogradé pour cette réponse. Certes, la réponse de polygenelubricants est beaucoup plus détaillée, mais j'ai utilisé cette fonction de nombreuses fois sans problème, y a-t-il une erreur quelconque ?
Je n'ai pas voté contre vous, mais votre algorithme a choisi 2*C(n,k)-1 fois. C'est-à-dire qu'en calculant choose(10,5)
il fera 503 appels récursifs (2*C(10,5)-1 = 2*252-1 = 504-1). Il n'a donc aucun espoir de calculer C(40,20), qui représente environ 138 milliards.
Je suis d'accord, il en va de même pour une implémentation de base de Fibonacci, ou pour tout autre algorithme qui bénéficie de la programmation dynamique. Pensez-vous que ma réponse (en particulier la suggestion de mémoriser la méthode) ne couvre pas suffisamment cela ?
J'essaie simplement de calculer le nombre de combinaisons de 2 cartes avec différentes tailles de jeux...
Pas besoin d'importer une bibliothèque externe - dès la définition de la combinaison, avec n
cartes qui seraient n*(n-1)/2
Question bonus : Cette même formule permet de calculer la somme du premier n-1
les entiers - vous voyez pourquoi ils sont identiques ? :)
Oui, il devrait. Vous ne voulez pas calculer d'énormes factorielles si vous êtes limité par la taille d'un fichier de type int
par exemple.
Vous pouvez effectuer une factorisation pour nettoyer un peu le résultat, mais cette définition donne toujours des nombres beaucoup plus grands que ceux que vous voulez utiliser. Pour obtenir les meilleurs résultats, un algorithme de choix ne devrait jamais calculer un nombre plus grand que le résultat - ces nombres deviennent assez vite grands comme ça.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
7 votes
Que se passe-t-il si le résultat déborde d'un int ? Est-ce important ? Voulez-vous que le résultat soit un BigInteger ?
2 votes
J'essaie simplement de calculer le nombre de combinaisons de 2 cartes avec différentes tailles de jeux (jusqu'à 52), ce qui ne devrait pas dépasser 1 326 (52 choisit 2).
13 votes
Vous avez réalisé que 52 ! est
80658175170943878571660636856403766975289505440883277824000000000000
? Parce qu'à en juger par la réponse que vous avez acceptée, vous ne semblez pas avoir pensé à la taille des nombres impliqués dans cette formule. Au fait, la réponse pour deux cartes est (n*(n-1))/2. Vous n'avez pas besoin d'une implémentation complète de 'n choose r' pour l'obtenir.0 votes
Ver stackoverflow.com/questions/1678690/ pour les considérations de mise en œuvre.
0 votes
Oh ok, merci, vous avez raison, j'avais des débordements d'entiers.
0 votes
@MarkByers. Une bonne implémentation de (n, r) ne calculera jamais les factorielles complètes !