Java 7+, n = 50 dans ~ 30 sec sur TIO
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Random;
class Main{
public static void main(String[] a){
int n=50;
Random randomGenerator = new Random();
int i = n+1;
int squaredN = n*n;
int[]randomIntegers = new int[i];
randomIntegers[n] = squaredN;
while(true){
for(i=n; i-->1; ){
randomIntegers[i] = randomGenerator.nextInt(squaredN);
}
Set<Integer> result = new HashSet<>();
Arrays.sort(randomIntegers);
for(i=n; i-->0; ){
result.add(randomIntegers[i+1] - randomIntegers[i]);
}
if(!result.contains(0) && result.size()==n){
System.out.println(result);
return;
}
}
}
}
Version non golfée de ma réponse pour la version code-golf de ce défi pour l'instant, avec un seul changement mineur: java.util.Random#nextInt(limit)
est utilisé à la place d' (int)(Math.random()*limit)
un entier dans la plage [0, n)
, car il est environ deux fois plus rapide .
Essayez-le en ligne.
Explication:
Approche utilisée:
Le code est divisé en deux parties:
- Générez une liste de
n
nombres entiers aléatoires qui totalisent n squared
.
- Ensuite, il vérifie si toutes les valeurs sont uniques et aucune n'est nulle, et s'il s'agit de falsey, il réessayera l'étape 1, en rinçant et en répétant jusqu'à ce que nous ayons un résultat.
L'étape 1 se fait avec les sous-étapes suivantes:
1) Générez un tableau de n-1
nombres entiers aléatoires dans la plage [0, n squared)
. Et ajoutez 0
et n squared
à cette liste. Cela se fait dans les O(n+1)
performances.
2) Ensuite, il triera le tableau avec le code intégré java.util.Arrays.sort(int[])
, cela se fait en O(n*log(n))
termes de performances, comme indiqué dans les documents:
Trie le tableau spécifié d'entiers dans l'ordre numérique croissant. L'algorithme de tri est un tri rapide ajusté, adapté de "Engineering a Sort Function" de Jon L. Bentley et M. Douglas McIlroy, Software-Practice and Experience, Vol. 23 (11) P. 1249-1265 (novembre 1993). Cet algorithme offre des performances n * log (n) sur de nombreux ensembles de données, ce qui entraîne la dégradation d'autres performances rapides en performances quadratiques.
3) Calculez la différence entre chaque paire. Cette liste résultante de différences contiendra des n
nombres entiers qui se résument à n squared
. Cela se fait dans les O(n)
performances.
Voici un exemple:
// n = 4, nSquared = 16
// n-1 amount of random integers in the range [0, nSquared):
[11, 2, 5]
// Add 0 and nSquared to it, and sort:
[0, 2, 5, 11, 16]
// Calculate differences:
[2, 3, 6, 5]
// The sum of these differences will always be equal to nSquared
sum([2, 3, 6, 5]) = 16
Ces trois étapes ci-dessus sont donc plutôt bonnes pour les performances, contrairement à l'étape 2 et à la boucle autour de l'ensemble, qui est une force brute de base. L'étape 2 est divisée en ces sous-étapes:
1) La liste des différences est déjà enregistrée dans a java.util.Set
. Il vérifiera si la taille de cet ensemble est égale à n
. Si c'est le cas, cela signifie que toutes les valeurs aléatoires que nous avons générées sont uniques.
2) Et il vérifiera également qu'il ne contient pas 0
dans l'ensemble, car le défi demande des valeurs aléatoires dans la plage [1, X]
, où X
est n squared
moins la somme de [1, ..., n-1]
, comme indiqué par @Skidsdev dans le commentaire ci-dessous.
Si l'une des deux options ci-dessus (toutes les valeurs ne sont pas uniques ou un zéro est présent), elle générera un nouveau tableau et se remettra à zéro en revenant à l'étape 1. Cela continue jusqu'à ce que nous ayons un résultat. Pour cette raison, le temps peut varier considérablement. Je l'ai vu finir en 3 secondes une fois sur TIO pour n=50
, mais aussi en 55 secondes une fois pour n=50
.
Preuve d'uniformité:
Je ne sais pas vraiment comment prouver cela pour être complètement honnête. Le java.util.Random#nextInt
est uniforme à coup sûr, comme décrit dans la documentation:
Renvoie la valeur pseudo-aléatoire suivante, uniformément distribuée int
, à partir de la séquence de ce générateur de nombres aléatoires. Le contrat général nextInt
est qu'une int
valeur est générée et renvoyée de manière pseudo-aléatoire. Les 2 32int
valeurs possibles sont produites avec une probabilité (approximativement) égale.
Les différences entre ces valeurs aléatoires (triées) elles-mêmes ne sont bien sûr pas uniformes, mais les ensembles dans leur ensemble sont uniformes. Encore une fois, je ne sais pas comment le prouver mathématiquement, mais voici un script qui mettra les 10,000
ensembles générés (pour n=10
) dans une carte avec un compteur , où la plupart des ensembles sont uniques; certains ont répété deux fois; et l'occurrence répétée maximale se situe généralement dans la plage [4,8]
.
Instructions d'installation:
Étant donné que Java est un langage assez bien connu avec de nombreuses informations disponibles sur la façon de créer et d'exécuter du code Java, je serai bref.
Tous les outils utilisés dans mon code sont disponibles en Java 7 (peut-être même déjà en Java 5 ou 6, mais utilisons 7 au cas où). Je suis à peu près sûr que Java 7 est déjà archivé, donc je suggère de télécharger Java 8 pour exécuter mon code.
Réflexions sur les améliorations:
Je voudrais trouver une amélioration pour la vérification des zéros et vérifier que toutes les valeurs sont uniques. Je pourrais vérifier 0
avant, en m'assurant que la valeur aléatoire que nous ajoutons au tableau n'est pas déjà dedans, mais cela signifierait quelques choses: le tableau devrait être un ArrayList
afin que nous puissions utiliser la méthode intégrée .contains
; une boucle while devrait être ajoutée jusqu'à ce que nous trouvions une valeur aléatoire qui ne figure pas encore dans la liste. Étant donné que la vérification de zéro est désormais effectuée avec .contains(0)
sur l'ensemble (qui n'est vérifié qu'une seule fois), il est probablement préférable que les performances le vérifient à ce stade, par rapport à l'ajout de la boucle avec .contains
sur la liste, qui sera vérifiée au moins une n
fois , mais probablement plus.
En ce qui concerne la vérification de l'unicité, nous n'avons que notre n
quantité d'entiers aléatoires qui résument n squared
après l'étape 1 du programme, donc seulement alors nous pouvons vérifier si tous sont uniques ou non. Il pourrait être possible de conserver une liste triable au lieu d'un tableau et de vérifier les différences entre les deux, mais je doute sérieusement que cela améliorera les performances que de simplement les mettre dans un Set
et vérifier si la taille de cet ensemble est n
une fois.