Un amigo mío está entrevistando para un trabajo. Una de las preguntas de la entrevista me hizo pensar, solo quería algunos comentarios.
Hay 2 enteros no negativos: i y j. Dada la siguiente ecuación, encuentre una solución (óptima) para iterar sobre iyj de tal manera que se ordene la salida.
2^i * 5^j
Entonces las primeras rondas se verían así:
2^0 * 5^0 = 1
2^1 * 5^0 = 2
2^2 * 5^0 = 4
2^0 * 5^1 = 5
2^3 * 5^0 = 8
2^1 * 5^1 = 10
2^4 * 5^0 = 16
2^2 * 5^1 = 20
2^0 * 5^2 = 25
Por más que lo intente, no puedo ver un patrón. ¿Tus pensamientos?
algorithm
optimization
hamming-numbers
smooth-numbers
Chris Eberle
fuente
fuente
2^2 < 5
pero2^3 > 5
entonces en ese punto aumentas j. Creo que puede producir la salida en O (n) en lugar de O (nlgn). @ tom-zynch dos bucles anidados es O (n ^ 2). Esta pregunta es muy válidaRespuestas:
Dijkstra deriva una solución elocuente en "Una disciplina de programación". Él atribuye el problema a Hamming. Aquí está mi implementación de la solución de Dijkstra.
fuente
Aquí hay una forma más refinada de hacerlo (más refinada que mi respuesta anterior, es decir):
imagina que los números se colocan en una matriz:
lo que necesita hacer es 'caminar' esta matriz, comenzando en
(0,0)
. También necesita realizar un seguimiento de cuáles son sus próximos movimientos posibles. Cuando comienzas(0,0)
solo tienes dos opciones:(0,1)
o bien(1,0)
: como el valor de(0,1)
es menor, eliges eso. luego haga lo mismo para su próxima opción(0,2)
o(1,0)
. Hasta el momento, tiene la siguiente lista:1, 2, 4
. Su próximo movimiento es(1,0)
porque el valor allí es menor que(0,3)
. Sin embargo, ahora tiene tres opciones para su próximo movimiento: o(0,3)
, o(1,1)
o(2,0)
.No necesita la matriz para obtener la lista, pero sí necesita hacer un seguimiento de todas sus opciones (es decir, cuando llegue a 125+, tendrá 4 opciones).
fuente
j
verifica por cada 1 salidaj ~ n^0.5
para el enésimo valor en una secuencia, ya que losn
valores llenan un área en eli x j
plano. Entonces este algo esO(n^1.5)
tiempo, conO(n^0.5)
espacio. Pero existe un algoritmo de tiempo lineal con la misma compatibilidad de espacion^0.5
, y el algoritmo de mini-montón de la respuesta a continuación esO(n*log(n))
tiempo con el mismon^0.5
espacio.Usa un montón mínimo.
Pon 1.
extracto-Min. Digamos que obtienes x.
Empuje 2x y 5x en el montón.
Repetir.
En lugar de almacenar x = 2 ^ i * 5 ^ j, puede almacenar (i, j) y utilizar una función de comparación personalizada.
fuente
Una solución basada en FIFO necesita menos capacidad de almacenamiento. Código de Python
salida:
fuente
Esto es muy fácil de hacer
O(n)
en lenguajes funcionales. La listal
de2^i*5^j
números puede definirse simplemente como1
y luego2*l
y5*l
fusionarse. Así es como se ve en Haskell:La
merge
función le da un nuevo valor en tiempo constante. También lo hacemap
y por lo tanto también lo hacel
.fuente
union
, ya que elimina los duplicados.merge
, como parte demergesort
, debe conservar duplicados provenientes de sus dos secuencias de entrada. VerData.List.Ordered
paquete para cosas relacionadas.Data.List.Ordered.union
. Eso lo convierte en una línea:xs = 1 : union (map (2*) xs) (map (5*) xs)
[1, 2, 4, 5,...]
por lo que incluye5*4
.Data.List.Ordered.union
función. No debe confundirse conData.List.union
.Debe realizar un seguimiento de los exponentes individuales de ellos y cuáles serían sus sumas.
entonces comienzas con
f(0,0) --> 1
ahora tienes que incrementar uno de ellos:entonces sabemos que 2 es el siguiente, también sabemos que podemos incrementar el exponente de i hasta que la suma supere 5.
Sigue yendo y viniendo de esta manera hasta que esté en su número de rondas.
fuente
f(*,2)
solo porque lo encontrastef(a1,b+1)>f(a2,b)
. Un enfoque incremental eventualmente generará un número ilimitado de pares vecinos a la región que ya ha generado.Usando programación dinámica puedes hacer esto en O (n). La verdad fundamental es que ningún valor de i y j puede darnos 0, y para obtener 1 ambos valores deben ser 0;
Siempre que llame a esta función, compruebe si i y j están configurados, si no son nulos, luego complete
TwoCount
yFiveCount
C ++ respuesta. Perdón por el mal estilo de codificación, pero tengo prisa :(
Obviamente, puede usar estructuras de datos distintas de la matriz para aumentar dinámicamente su almacenamiento, etc. Esto es solo un boceto para demostrar que funciona.
fuente
O(exp(sqrt(n)))
, para producirn
números de la secuencia. Existe un algoritmo lineal , por ejemplo, tal como lo proporciona ThomasAhle.O(n)
significaban
ser el último valor, no el número de elementos impresos, lo cual no es correcto. No sé cómo funcionan los lenguajes funcionales, o cómo funciona la fusión en tiempo constante, pero su respuesta recibió mi voto positivo¿Por qué no intentar mirar esto desde la otra dirección? Use un contador para probar las posibles respuestas contra la fórmula original. Perdón por el pseudocódigo.
fuente
O(4^sqrt(n))
porque elnth
número de la secuencia es de aproximadamente ese tamaño.Esta es la entrada relevante en OEIS.
Parece posible obtener la secuencia ordenada generando los primeros términos, digamos
y luego, a partir del segundo término, multiplicando por 4 y 5 para obtener los siguientes dos
y así...
Intuitivamente, esto parece correcto, pero por supuesto falta una prueba.
fuente
Sabes que log_2 (5) = 2,32. De esto observamos que 2 ^ 2 <5 y 2 ^ 3> 5.
Ahora mira una matriz de posibles respuestas:
Ahora, para este ejemplo, elija los números en orden. Allí ordenar sería:
Tenga en cuenta que cada fila comienza 2 columnas detrás de la fila que lo inicia. Por ejemplo, i = 0 j = 1 viene directamente después de i = 2 j = 0.
Por lo tanto, un algoritmo que podemos derivar de este patrón es (supongamos que j> i):
NOTA: El código aquí limita los valores de los exponentes de i y j a menos de 10. Puede extender fácilmente este algoritmo para que se ajuste a cualquier otro límite arbitrario.
NOTA: El tiempo de ejecución de este algoritmo es O (n) para las primeras n respuestas.
NOTA: La complejidad del espacio para este algoritmo es O (1)
fuente
Mi implementación se basa en las siguientes ideas:
Ejemplo:
Código en Java:
fuente
calcular los resultados y ponerlos en una lista ordenada, junto con los valores para
i
yj
fuente
2^n*5^n
pero no2^(n+1)*5^(n-1)
cuál es más pequeño.i
's yj
' s, ¿no? De lo contrario, nunca llegará al estado de clasificación y, por lo tanto, nunca devolverá un solo valor. Pero para cualquier límiten
que elija, su lista será defectuosa.i
yj
.2^i*5^j
valores, y luego los ordena. Si no tiene un número limitado de "resultados", ¿cómo va a llegar al paso de clasificación?El algoritmo implementado por user515430 por Edsger Dijkstra (http://www.cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF) es probablemente lo más rápido posible. Llamo a cada número que es una forma de
2^i * 5^j
"número especial". Ahora la respuesta de vlads seríaO(i*j)
pero con un algoritmo doble, uno para generar los números especialesO(i*j)
y otro para ordenarlos (según el artículo vinculado tambiénO(i*j)
.Pero revisemos el algoritmo de Dijkstra (ver más abajo). En este caso,
n
la cantidad de números especiales que estamos generando es igual ai*j
. Estamos dando vueltas una vez,1 -> n
y en cada vuelta realizamos una acción constante. Entonces este algoritmo también lo esO(i*j)
. Y con una constante bastante rápida y ardiente también.Mi implementación en C ++ con GMP (contenedor de C ++) y dependencia
boost::lexical_cast
, aunque eso se puede eliminar fácilmente (soy flojo y ¿quién no usa Boost?). Compilado cong++ -O3 test.cpp -lgmpxx -o test
. En Q6600 Ubuntu 10.10time ./test 1000000
da1145ms
.fuente
Si dibuja una matriz con i como fila y j como columna, puede ver el patrón. Comience con i = 0 y luego atraviese la matriz subiendo 2 filas y derecha 1 columna hasta llegar a la parte superior de la matriz (j> = 0). Luego vaya i + 1, etc.
Entonces para i = 7 viajas así:
Y para i = 8:
Aquí está en Java subiendo a i = 9. Imprime la posición de la matriz (i, j) y el valor.
fuente
Mi intuición :
Si tomo el valor inicial como 1 donde i = 0, j = 0, entonces puedo crear los siguientes números como (2 ^ 1) (5 ^ 0), (2 ^ 2) (5 ^ 0), (2 ^ 0) * (5 ^ 1), ... es decir, 2,4,5 ..
Digamos que en cualquier momento mi número es x. entonces puedo crear los siguientes números de las siguientes maneras:
Explicacion :
Prueba de funcionamiento
Comencemos con x = 1.
Los siguientes tres números son 1 * 2, 1 * 4, 1 * 5 [2,4,5]; Arr [1,2,4,5]
Ahora x = 2
Los siguientes tres números son [4,8,10] {Dado que 4 ya ocurrieron, lo ignoraremos} [8,10]; Arr [1,2,4,5,8,10]
Ahora x = 4
Siguientes tres números [8,16,20] {8 ya ocurrió ignorarlo} [16,20] Arr [1,2,4,5,8,10,16,20]
x = 5
Los siguientes tres números [10,20,25] {10,20} ya están agregados [25] Arr [1,2,4,5,8,10,16,20,25]
Condición de terminación
Análisis
fuente
Simplemente tenía curiosidad por saber qué esperar la próxima semana y he encontrado esta pregunta.
Creo que la idea es 2 ^ i no aumenta en esos grandes pasos como 5 ^ j. Por lo tanto, aumente i siempre que el próximo paso j no sea mayor
El ejemplo en C ++ (Qt es opcional):
La salida:
fuente
Aqui esta mi solucion
Resultado:
fuente
Sé que probablemente estoy equivocado, pero aquí hay una heurística muy simple, ya que no involucra muchos números como 2,3,5. Sabemos que para cualquier i, j 2 ^ i * 5 ^ j la siguiente secuencia sería 2 ^ (i-2) * 5 ^ (j + 1). Al ser un google q debe tener una solución simple.
Esto produce resultados como:
fuente
Si sigue lo que realmente sucede cuando incrementamos i o j en la expresión
2^i * 5^j
, está multiplicando por otros 2 u otros 5. Si reformulamos el problema como - dado un valor particular de i y j, ¿cómo encontraría el siguiente mayor valor, la solución se hace evidente.Aquí están las reglas que podemos enumerar de manera bastante intuitiva:
i > 1
) en la expresión, debemos reemplazarlos con un 5 para obtener el siguiente número más grande. Por lo tanto,i -= 2
yj += 1
.j > 0
), debemos reemplazarlo con tres 2s. Asíj -= 1
yi += 3
.i += 1
.Aquí está el programa en Ruby:
fuente
Si se nos permite usar Java Collection, entonces podemos tener estos números en O (n ^ 2)
¡Aquí powerLimit debe inicializarse con mucho cuidado! Dependiendo de cuántos números quieras.
fuente
Aquí está mi intento con Scala:
Salida:
fuente