Números de Hamming


20

Dado un número entero positivo, imprima esa cantidad de números de Hamming , en orden.

Reglas:

  • La entrada será un entero positivo n1,000,000
  • La salida debe ser los primeros n términos de https://oeis.org/A051037
  • El tiempo de ejecución debe ser <1 minuto
  • Este es el ; el código más corto gana

2
¿Qué objetivo debe tener una respuesta? ¿Golf? Algoritmo más efectivo? ¿Solo busca métodos de solución?
Nakilon

Perdón por no ser específico. No lo he resuelto yo mismo, así que no estoy seguro de si los límites que puse son razonables. Por favor hagamelo saber.
grokus


3
1 es un número de Hamming, por lo que imprimir 1,000,000 1s cumple con sus especificaciones. También estará en orden, es decir, no una secuencia desordenada. :)
Will Ness

Respuestas:


7

Haskell, 101 97 92+ | n | caracteres

h=1:m 2h&m 3h&m 5h
m=map.(*)
c@(a:b)&o@(m:n)|a<m=a:b&o|a>m=m:c&n|0<1=a:b&n
main=print$take 1000000h

Calcula el millón completo en 3.7s en la máquina que probé (de forma variable más si realmente desea que se almacene la salida)

Sin golf:

-- print out the first million Hamming numbers
main = print $ take 1000000 h

-- h is the entire Hamming sequence.
-- It starts with 1; for each number in the
-- sequence, 2n, 3n and 5n are also in.
h = 1 : (m 2 h) & (m 3 h) & (m 5 h)

-- helper: m scales a list by a constant factor
m f xs = map (f*) xs

-- helper: (&) merges two ordered sequences
a@(ha:ta) & b@(hb:tb)
    |    ha < hb = ha : ta & b
    |    ha > hb = hb :  a & tb
    |  otherwise = ha : ta & tb

Todo Haskell es notablemente bueno para: definir una lista como una función perezosa de sí misma, de una manera que realmente funcione.


1
No obtienes el parámetro entero positivo, que agrega más tamaño a tu código
Zhen

@Zhen El parámetro entero positivo es el penúltimo token, y su tamaño se declara por adelantado en el encabezado.
JB

3

Personajes de Python 181

h=[]        
h.append(1)
n=input()
i=j=k=0
while n:
    print h[-1]
    while h[i]*2<=h[-1]:
        i+=1
    while h[j]*3<=h[-1]:
        j+=1
    while h[k]*5<=h[-1]:
        k+=1
    h.append(min(h[i]*2,h[j]*3,h[k]*5))
    n-=1

¿Cómo es esto 181 caracteres? He guardado esto en un archivo, eliminando el espacio en blanco después h=[], usando una distancia mínima de tabulación y saltos de línea de un solo carácter, y el tamaño del archivo termina siendo 187 bytes.
nitro2k01

1
Optimización de todos modos ... Trivial: h=[1]. Además, proporcione un número directamente en el código fuente, para guardar caracteres para los números <1000000.
nitro2k01

Y vaya, lo siento, no me di cuenta de que la respuesta es muy antigua.
nitro2k01

@ nitro2k01, hago 183 caracteres. (Hay algunos espacios en blanco al final de la primera línea, y la sangría debe ser un espacio para un nivel y una pestaña para dos niveles).
Peter Taylor

1

Ruby - 154 231 caracteres

def k i,n;(l=Math).log(i,2)*l.log(i,3)*l.log(i,5)/6>n end
def l i,n;k(i,n)?[i]:[i]+l(5*i,n)end
def j i,n;k(i,n)?[i]:[i]+j(3*i,n)+l(5*i,n)end
def h i,n;k(i,n)?[i]:[i]+h(2*i,n)+j(3*i,n)+l(5*i,n)end
puts h(1,n=gets.to_i).sort.first n

Y ahora es lo suficientemente rápido, sin duda, todavía puede jugar mucho golf.

→ time echo 1000000 | ruby golf-hamming.rb | wc
1000000 1000000 64103205
echo 1000000  0.00s user 0.00s system 0% cpu 0.003 total
ruby golf-hamming.rb  40.39s user 0.81s system 99% cpu 41.229 total
wc  1.58s user 0.05s system 3% cpu 41.228 total

1

Perl, 94 caracteres (pero demasiado lento)

use List::Util min;
$\=$/;$h{1}=();delete$h{$_=min keys%h},print,@h{$_*2,$_*3,$_*5}=()for 1..<>

Sin golf:

use List::Util 'min';
my %hamming;
my $up_to = <>;
$hamming{1} = (); # The value is undef, but the key exists!
for (1 .. $up_to) {
    my $next = min( keys %hamming );
    delete $hamming{$next}; # We're done with this one
    print $next, "\n";
    @hamming{ $next * 2, $next * 3, $next * 5 } = (); # Create keys for the multiples
} # Rinse, repeat

Toma 11 minutos calcular los primeros 100,000 números, y ni siquiera quiero pensar en 1,000,000. Obtiene los primeros 10,000 en un orden de 3 segundos; es solo algo parecido a O (n ^ 2) :(


1

APL (Dyalog Classic) , 34 23 bytes

{⍺⍴{⍵[⍋⍵]}∪,⍵∘.×⍳5}⍣≡∘1

Pruébalo en línea!

n=1000000

{⍺⍴{⍵[⍋⍵]}∪,⍵∘.×⍳5}⍣≡∘1     Monadic function:
{⍺⍴{⍵[⍋⍵]}∪,⍵∘.×⍳5}         Define the following helper function g(⍺,⍵):
             ⍵∘.×⍳5             Make a multiplication table between  and (1 2 3 4 5).
                                (Including 4 is unnecessary but saves bytes.)
            ,                   Flatten the table into an array.
                               Keep unique elements.
    {⍵[⍋⍵]}                     Grade up the array and access it at those indices.
                                (This is the APL idiom to sort an array.)
 ⍺⍴                             Keep the first  elements; pad by repeating the array.
{⍺⍴{⍵[⍋⍵]}∪,⍵∘.×⍳5}⍣≡       Repeatedly apply g with some fixed left argument
                             until a fixed point is reached.
                             At this point we have a dyadic function that takes
                             n on the left and the starting value on the right,
                             and returns multiples of the n Hamming numbers.
                      1     Fix 1 as the right argument.


FYI, {⍺⍴∧∪,⍵×⍀⍳5}`⍣≡∘1en extendido. (Retroceso necesario debido a error).
Adám

0

Haskell, 71

h n = drop n $ iterate (\(_,(a:t))-> (a,union t [2*a,3*a,5*a])) (0,[1])

Salida

*Main> map fst $ take 20 $ h 1
[1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36]

La especificación requiere que imprima, por lo que debe contarse el código para imprimir. Esto también permite una comparación justa con la otra implementación de Haskell.
Peter Taylor

@PeterTaylor ¿Cuántos personajes crees que debería agregar?
Timtech

0

Ursala, 103

#import std
#import nat
smooth"p" "n" = ~&z take/"n" nleq-< (rep(length "n") ^Ts/~& product*K0/"p") <1>

Salida paramain = smooth<2,3,5>* nrange(1,20)

<1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36>

0

Mathematica, 54 bytes

Sort[1##&@@@({2,3,5}^#&/@Tuples[0~Range~#,3])]~Take~#&

Ineficiente pero corta función pura. Calcula todos los productos de la forma 2^i * 3^j * 5^kpara 0 <= i, j, k <= #( #es el primer argumento de la función), luego Sorts ellos y Takes solo el primero #.


1
De alguna manera no creo que realizar cálculos 1e18 vaya a suceder en menos de un minuto.
Jonathan Allan

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.