Java 7+, n = 50 in ~ 30 sec su 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;
}
}
}
}
La versione non golfata della mia risposta per la versione code-golf di questa sfida per ora, con solo una piccola modifica: java.util.Random#nextInt(limit)
viene utilizzata al posto di (int)(Math.random()*limit)
un numero intero nell'intervallo [0, n)
, poiché è circa il doppio più veloce .
Provalo online.
Spiegazione:
Approccio utilizzato:
Il codice è diviso in due parti:
- Genera un elenco di
n
quantità di numeri interi casuali da sommare a n squared
.
- Quindi controlla se tutti i valori sono univoci e nessuno è zero e se uno dei due è falso, proverà nuovamente a eseguire il passaggio 1, sciacquando e ripetendo fino a quando non si ottiene un risultato.
Il passaggio 1 viene eseguito con i seguenti passaggi secondari:
1) Genera un array di n-1
quantità di numeri interi casuali nell'intervallo [0, n squared)
. E aggiungi 0
e n squared
a questo elenco. Questo è fatto in termini di O(n+1)
prestazioni.
2) Quindi ordinerà l'array con l'integrato java.util.Arrays.sort(int[])
, questo viene fatto in termini di O(n*log(n))
prestazioni, come indicato nei documenti:
Ordina la matrice di in specificata in ordine numerico crescente. L'algoritmo di ordinamento è un quicksort sintonizzato, adattato da Jon L. Bentley e M. Douglas McIlroy "Engineering a Sort Function", Software-Practice and Experience, Vol. 23 (11) P. 1249-1265 (novembre 1993). Questo algoritmo offre n * log (n) prestazioni su molti set di dati che causano il degrado di altri quicksorts in prestazioni quadratiche.
3) Calcola la differenza tra ogni coppia. Questo elenco risultante di differenze conterrà n
numeri interi che sommano n squared
. Questo è fatto in termini di O(n)
prestazioni.
Ecco un esempio:
// 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
Quindi questi tre passaggi sopra sono abbastanza buoni per le prestazioni, a differenza del passaggio 2 e del ciclo attorno a tutto, che è una forza bruta di base. Il passaggio 2 è suddiviso in questi passaggi secondari:
1) L'elenco delle differenze è già stato salvato in a java.util.Set
. Verificherà se la dimensione di questo set è uguale a n
. Se lo è, significa che tutti i valori casuali che abbiamo generato sono unici.
2) E verificherà anche che non contenga alcun valore 0
nel Set, poiché la sfida richiede valori casuali nell'intervallo [1, X]
, dove X
è n squared
meno la somma di [1, ..., n-1]
, come affermato da @Skidsdev nel commento qui sotto.
Se una delle due opzioni sopra (non tutti i valori sono univoci o è presente uno zero), verrà generato un nuovo array e impostato nuovamente ripristinando il passaggio 1. Questo continua fino a quando non si ottiene un risultato. Per questo motivo, il tempo può variare abbastanza. L'ho visto finire in 3 secondi una volta su TIO per n=50
, ma anche in 55 secondi una volta per n=50
.
Prova di uniformità:
Non sono del tutto sicuro di come dimostrarlo completamente onesto. L' java.util.Random#nextInt
uniforme è sicura, come è descritto nei documenti:
Restituisce il successivo valore pseudocasuale, distribuito uniformemente int
dalla sequenza di questo generatore di numeri casuali. Il contratto generale di nextInt
è che un int
valore viene generato e restituito in modo pseudocasuale. Tutti i 2 32 possibili int
valori sono prodotti con (approssimativamente) uguale probabilità.
Le differenze tra questi valori casuali (ordinati) non sono ovviamente uniformi, ma gli insiemi nel loro insieme sono uniformi. Ancora una volta, non sono sicuro di come dimostrarlo matematicamente, ma ecco uno script che metterà i 10,000
set generati (per n=10
) in una mappa con un contatore , dove la maggior parte dei set sono unici; alcuni ripetuti due volte; e la ricorrenza massima ripetuta è generalmente nell'intervallo [4,8]
.
Istruzioni per l'installazione:
Poiché Java è un linguaggio piuttosto noto con molte informazioni disponibili su come creare ed eseguire il codice Java, lo terrò breve.
Tutti gli strumenti utilizzati nel mio codice sono disponibili in Java 7 (forse anche già in Java 5 o 6, ma usiamo 7 per ogni evenienza). Sono abbastanza sicuro che Java 7 sia già archiviato, quindi suggerirei di scaricare Java 8 per eseguire il mio codice.
Considerazioni sui miglioramenti:
Vorrei trovare un miglioramento per il controllo degli zeri e verificare che tutti i valori siano univoci. Potrei verificare 0
prima, assicurandomi che il valore casuale che aggiungiamo all'array non sia già presente, ma significherebbe un paio di cose: l'array dovrebbe essere un ArrayList
così da poter usare il metodo incorporato .contains
; un ciclo while dovrebbe essere aggiunto fino a quando non abbiamo trovato un valore casuale che non è ancora nella lista. Poiché il controllo dello zero è ora eseguito con .contains(0)
sul set (che viene verificato solo una volta), è molto meglio che le prestazioni lo controllino in quel punto, rispetto all'aggiunta del loop con .contains
sull'elenco, che verrà verificato almeno n
volte , ma molto probabilmente di più.
Per quanto riguarda il controllo di unicità, abbiamo solo la nostra n
quantità di numeri interi casuali che si sommano n squared
dopo il passaggio 1 del programma, quindi solo così possiamo verificare se tutti sono unici o no. Potrebbe essere possibile mantenere un elenco ordinabile anziché un array e verificare le differenze tra loro, ma dubito seriamente che migliorerà le prestazioni piuttosto che inserirle in un Set
e verificare se la dimensione di quel set è n
una volta.