Hamming numbers


19

Dado um número inteiro positivo, imprima muitos números hamming , em ordem.

Regras:

  • A entrada será um número inteiro positivon1,000,000
  • A saída deve ser os primeiros n termos de https://oeis.org/A051037
  • O tempo de execução deve ser <1 minuto
  • Isso é ; o código mais curto vence

2
Qual objetivo uma resposta deveria ter? Golfe? Algoritmo mais eficaz? Apenas pesquisando métodos de solução?
Nakilon

Desculpe por não ser específico. Eu não resolvi isso sozinho, então não tenho certeza se os limites que coloco são razoáveis. Por favor deixe-me saber.
grokus


3
1 é um número de Hamming, portanto, imprimir 1.000.000 1s está em conformidade com suas especificações. Também estará em ordem, ou seja, não será uma sequência não ordenada. :)
Ness Will

Respostas:


7

Haskell, 101 97 92+ | n | personagens

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 o milhão completo em 3,7s na máquina em que testei (variavelmente mais se você realmente deseja que a saída seja armazenada)

Ungolfed:

-- 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 é notoriamente bom em: definir uma lista como uma função preguiçosa de si mesma, de uma maneira que realmente funcione.


1
Você não ganha o parâmetro inteiro positivo, que acrescentar mais tamanho ao seu código
Zhen

@Zhen O parâmetro inteiro positivo é o penúltimo token e seu tamanho é declarado antecipadamente no cabeçalho.
JB

3

Python 181 caracteres

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

Como é este 181 caracteres? Salvei isso em um arquivo, removendo o espaço em branco depois h=[], usando uma distância mínima de tabulação e quebras de linha de um único caractere, e o tamanho do arquivo acaba sendo de 187 bytes.
Nitro2k01

1
Otimização de qualquer maneira ... Trivial: h=[1]. Além disso, forneça um número diretamente no código-fonte, para salvar caracteres para números <1000000.
Nitro2k01

E opa, desculpe, não percebi que a resposta é super antiga.
Nitro2k01

@ nitro2k01, eu faço 183 caracteres. (Há algum espaço em branco à direita no final da primeira linha e o recuo deve ser um espaço para um nível e uma guia para dois níveis).
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

E agora é rápido o suficiente, há definitivamente muito golfe que ainda pode acontecer.

→ 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 (mas muito lento)

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

Ungolfed:

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

Demora 11 minutos para calcular os primeiros 100.000 números, e eu nem quero pensar em 1.000.000. Ele obtém os primeiros 10.000 em 3 segundos arrumados; é apenas algo parecido com O (n ^ 2) :(


1

APL (Dyalog Classic) , 34 23 bytes

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

Experimente online!

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.

Baralhar as coisas por aí salva quatro:1↓0 1{⍺↑{⍵[⍋⍵]}∪,⍵∘.×⍳5}⍣≡⍨1+⊢
Adám

FYI, {⍺⍴∧∪,⍵×⍀⍳5}`⍣≡∘1em Extended. (Backtick necessário devido a um bug.)
Adám 08/02

0

Haskell, 71

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

Resultado

*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]

A especificação exige que você imprima, portanto, o código a ser impresso deve ser contado. Isso também permite uma comparação justa com a outra implementação do Haskell.
Peter Taylor

@PeterTaylor Quantos caracteres você acha que devo adicionar?
Timtech

0

Ursala, 103

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

Saída 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~#&

Função pura ineficiente, mas curta. Calcula todos os produtos do formulário 2^i * 3^j * 5^kpara 0 <= i, j, k <= #( #é o primeiro argumento da função) e, em seguida, Sorts e Takes apenas o primeiro #.


1
De alguma forma, acho que a execução dos cálculos 1e18 acontecerá em menos de um minuto.
Jonathan Allan

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.