Java 7+, n = 50 en ~ 30 segundos en 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 versión sin golf de mi respuesta para la versión de código de golf de este desafío por ahora, con solo un cambio menor: java.util.Random#nextInt(limit)
se usa en lugar de (int)(Math.random()*limit)
un número entero en el rango [0, n)
, ya que es aproximadamente el doble de rápido .
Pruébalo en línea.
Explicación:
Enfoque utilizado:
El código se divide en dos partes:
- Genere una lista de la
n
cantidad de enteros aleatorios que suman n squared
.
- Luego verifica si todos los valores son únicos y ninguno es cero, y si alguno es falso, intentará el paso 1 nuevamente, enjuagando y repitiendo hasta que tengamos un resultado.
El paso 1 se realiza con los siguientes subpasos:
1) Genere una matriz de n-1
cantidad de enteros aleatorios en el rango [0, n squared)
. Y agregue 0
y n squared
a esta lista. Esto se hace en O(n+1)
rendimiento.
2) Luego ordenará la matriz con la función incorporada java.util.Arrays.sort(int[])
. Esto se hace en O(n*log(n))
rendimiento, como se indica en los documentos:
Ordena la matriz especificada de entradas en orden numérico ascendente. El algoritmo de clasificación es una selección rápida ajustada, adaptada de Jon L. Bentley y M. Douglas McIlroy "Ingeniería de una función de clasificación", Software-Practice and Experience, vol. 23 (11) P. 1249-1265 (noviembre de 1993). Este algoritmo ofrece un rendimiento n * log (n) en muchos conjuntos de datos que hacen que otros clasificaciones rápidas se degraden a un rendimiento cuadrático.
3) Calcular la diferencia entre cada par. Esta lista resultante de diferencias contendrá n
enteros que suman n squared
. Esto se hace en O(n)
rendimiento.
Aquí un ejemplo:
// 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
Entonces, estos tres pasos anteriores son bastante buenos para el rendimiento, a diferencia del paso 2 y el ciclo alrededor de todo, que es una fuerza bruta básica. El paso 2 se divide en estos pasos secundarios:
1) La lista de diferencias ya está guardada en a java.util.Set
. Verificará si el tamaño de este conjunto es igual a n
. Si es así, significa que todos los valores aleatorios que generamos son únicos.
2) Y también verificará que no contiene ningún 0
en el Conjunto, ya que el desafío solicita valores aleatorios en el rango [1, X]
, donde X
es n squared
menos la suma de [1, ..., n-1]
, como lo indica @Skidsdev en el comentario a continuación.
Si alguna de las dos opciones anteriores (no todos los valores son únicos o hay un cero presente), generará una nueva matriz y se establecerá nuevamente restableciendo el paso 1. Esto continúa hasta que tengamos un resultado. Debido a esto, el tiempo puede variar bastante. Lo he visto terminar en 3 segundos una vez en TIO durante n=50
, pero también en 55 segundos una vez n=50
.
Prueba de uniformidad:
No estoy completamente seguro de cómo demostrar que esto es completamente honesto. El java.util.Random#nextInt
uniforme es seguro, como se describe en los documentos:
Devuelve el siguiente valor pseudoaleatorio, distribuido uniformemente int
de la secuencia de este generador de números aleatorios. El contrato general de nextInt
es que un int
valor se genera y devuelve pseudoaleatoriamente. Los 2 32int
valores posibles se producen con (aproximadamente) la misma probabilidad.
Por supuesto, las diferencias entre estos valores aleatorios (ordenados) no son uniformes, pero los conjuntos en su conjunto son uniformes. Nuevamente, no estoy seguro de cómo probar esto matemáticamente, pero aquí hay un script que colocará los 10,000
conjuntos generados (para n=10
) en un Mapa con un contador , donde la mayoría de los conjuntos son únicos; algunos repiten dos veces; y la ocurrencia repetida máxima generalmente está en el rango [4,8]
.
Instrucciones de instalación:
Dado que Java es un lenguaje bastante conocido con mucha información disponible sobre cómo crear y ejecutar código Java, lo mantendré breve.
Todas las herramientas utilizadas en mi código están disponibles en Java 7 (tal vez incluso en Java 5 o 6, pero usemos 7 por si acaso). Sin embargo, estoy bastante seguro de que Java 7 ya está archivado, por lo que sugeriría descargar Java 8 para ejecutar mi código.
Reflexiones sobre mejoras:
Me gustaría encontrar una mejora para la verificación de ceros y verificar que todos los valores son únicos. Podría comprobar 0
antes, asegurándome de que el valor aleatorio que agreguemos a la matriz no esté ya en él, pero significaría un par de cosas: la matriz debería ser una ArrayList
para que podamos usar el método incorporado .contains
; se debe agregar un ciclo while hasta que hayamos encontrado un valor aleatorio que aún no esté en la Lista. Dado que la comprobación de cero ahora se realiza con .contains(0)
el Set (que solo se verifica una vez), lo más probable es que el rendimiento lo verifique en ese punto, en comparación con agregar el ciclo con .contains
en la Lista, que se verificará al menos n
veces , pero muy probablemente más.
En cuanto a la verificación de unicidad, solo tenemos nuestra n
cantidad de enteros aleatorios que suman n squared
después del paso 1 del programa, por lo que solo entonces podemos verificar si todos son únicos o no. Puede ser posible mantener una Lista ordenable en lugar de una matriz, y verificar las diferencias entre ellas, pero dudo seriamente que mejore el rendimiento que solo ponerlas en una Set
y verificar si el tamaño de ese Conjunto es n
una vez.