Gere a sequência figura-figura de Hofstadter

16

Em Gödel, Escher, Bach , Douglas Hofstadter introduz uma sequência inteira que é geralmente chamada de sequência figura-figura:

2, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, ...

Você pode gostar de elaborar a definição da sequência como parte do desafio, mas se não puder ou não quiser descobrir, poderá encontrá-la no OEIS como sequência A030124 e uma definição um pouco mais clara na Wikipedia .

Escreva um programa ou função que, fornecido nvia STDIN, ARGV ou argumento de função, imprima uma lista dos primeiros nnúmeros da sequência em STDOUT em qualquer formato razoável de lista.

Este é o código golf, a solução mais curta em bytes vence.

Martin Ender
fonte

Respostas:

6

CJam, 38 30 29 21 bytes

li_3*,2>\{(_pX+:X-}*;

Experimente online.

Como funciona

li                     " Read an integer N from STDIN.              ";
  _3*,2>               " Push S := [ 2 3 ... (N * 3 - 1) ].         ";
        \{        }*   " Do the following N times:                  ";
          (            " Shift an integer I from S.                 ";
           _p          " Print a copy of I, followed by a linefeed. ";
             X+:X      " Execute X += I. (X is initialized to 1.)   ";
                 -     " Remove X from S.                           ";
                    ;  " Discard S from the stack.                  ";

Exemplo de execução

$ cjam <(echo 'li_3*,2>\{(_pX+:X-}*;') <<< 20
2
4
5
6
8
9
10
11
13
14
15
16
17
19
20
21
22
23
24
25
Dennis
fonte
Você perdeu o aditsu ao digitar o URL do intérprete
Decay Beta
@BetaDecay então porque não editar para corrigi-lo;)
Martin Ender
@ Martin, eu não acho que tinha rep representante suficiente ...
Decay Beta
2
@BetaDecay Você não, mas ainda pode sugeri-los (o que dá até 2 repetições se eles forem aceitos).
Martin Ender
Eu me senti tão esperto por jogar fora 8 bytes adicionais do meu código. Então eu percebi que ele agora faz exatamente o mesmo que as respostas de histocrat, matsjoyce e Peter Taylor ...
Dennis
5

Ruby, 54 48

f=->n{x=1
b=*2..n*n
n.times{b-=[x+=p(b.shift)]}}

Demo

Edit: Golfed isso um pouco mais uma vez eu percebi que não preciso manter a sequência completa de complemento na memória. Eis como funciona agora: Usamos xpara rastrear o maior número computado na sequência do complemento e bé um pool de candidatos à sequência. nvezes, produzimos o menor elemento restante be o adicionamos xpara calcular o próximo número na sequência do complemento. Em seguida, removemos os dois números do pool de candidatos, para que sempre apresentemos o menor número que ainda não foi adicionado a nenhuma sequência.

Truques de golfe em Ruby: A sintaxe lambda estável é mais curta que uma definição de método. O requisito que a saída é fornecida para STDOUT em vez de como valor de retorno inspirou-me a usar o fato de que o valor de retorno p(x)é x, o qual normalmente não me lembro porque não é o caso da versão Ruby usada no Anarchy Golf.

histocrata
fonte
11
Como funciona?
proud haskeller
11
FWIW você poderia usar 2..2*n. Eu tenho que usá-lo n*nporque estou fazendo b = [x]^bisso de maneira eficaz . Preciso que o maior elemento bseja maior que o maior valor x, mas você b -= [x]só precisa que bcontenha o maior valor possível da sequência de saída.
Peter Peter Taylor
5

Haskell, 67 61 60 56 55 53 caracteres

g n=take n$2:4:h
a#(x:s)=[a..x-2]++x#s
h=5#scanl(+)8h

de volta ao primeiro algoritmo.

esta solução calcula a sequência do complemento somando os elementos iniciais da sequência. depois calcula a sequência como todos os números entre os números de sequência do complemento.

(#)é a função que calcula os números entre a sequência do complemento.
hé a própria sequência.
gé a função que responde à pergunta.

a função g é definida para tirar apenas a quantidade necessária de elementos de h.

sutilezas:

hé realmente a sequência da figura, exceto pelos 2 primeiros elementos.
não a sequência do complemento é calculada, mas a sequência do complemento com 1 adicionado para cada elemento.
essas duas sutilezas são a razão scanl(+)8h(que é o código para a sequência do complemento (exceto os 2 primeiros elementos) com 1s adicionados) 8. é para o terceiro elemento da sequência do complemento com 1 adicionado a ele.
a razão que o cálculo não está faltando os dois primeiros elementos é porque eles são adicionados gno 2:4:h.

exemplo:

>g 50
[2,4,5,6,8,9,10,11,13,14,15,16,17,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,57,58,59]
orgulhoso haskeller
fonte
4

GolfScript ( 24 21 bytes)

~.3*,1>\{(\(.p@+\|}*;

Demonstração online

Isso começou de maneira bem diferente, mas acabou convergindo para uma porta GolfScript da solução Ruby do histocrat , antes que Dennis fizesse algumas sugestões que a levassem em uma direção um pouco diferente. Em particular, imprimir os números à medida que os identificamos economiza bastante em reuni-los em uma matriz para impressão no final; O motivo é que isso significa que em nenhum momento precisamos nos preocupar com mais de 3 itens na pilha.

Dissecação

~.3*,           # Eval input n, dup, multiply by 3, make list [0 1 ... 3n-1]
1>              # Discard 0, which is part of neither sequence
\{              # Execute n times: stack contains pool of numbers not yet seen
                # in either sequence and the first element of it is the next element of the
                # complement sequence
  (\(           #   Pop two numbers from the start of the pool: stack is
                #     pool[0] pool[2..max] pool[1]
  .p            #   Print pool[1]
  @+            #   Rotate pool[0] to top and add to pool[1]
  \|            #   Place pool[0]+pool[1] at the start of the pool and
                #   (this is the clever bit) remove it from later in the pool
}*
;               # Discard the unused remainder of the pool
Peter Taylor
fonte
Se você substituir ^por \-, poderá substituir ).*por 3*. Isso não salva nenhum bytes, mas reduz drasticamente o tempo de execução e o uso de memória. - Você poderá salvar um byte mantendo o número inteiro na parte superior da matriz. O loop terá a mesma contagem de bytes, mas a inicialização será um byte menor.
Dennis
2
A união do conjunto funciona ainda melhor que a diferença:~.3*,1>\{(\(.p@+\|}*;
Dennis
3

J - 28 car

Função tomada ncomo argumento.

($+/\(-.~2+i.)&:>:+/)^:_&2 4

Executamos uma função, com o nargumento esquerdo, repetidamente no argumento direito até que não produza alteração. O argumento para começar é a lista 2 4.

Na própria função, pegamos as somas parciais +/\e a soma total +/e depois incrementamos as duas com &:>:. Em seguida, geramos todos os números inteiros de 2 para um que seja mais que soma total ( 2+i.) e definimos subtrair ( -.) as somas parciais, deixando uma sequência de figura-figura mais longa por definição. Por fim, reduzimos ou estendemos ciclicamente a lista n.

O resultado é que 2 4se torna 3 7, e isso é removido da 2..8partida 2 4 5 6 8. Após outra rodada, 2 4 5 6 8torna- 3 7 12 18 26se

2 4 5 6 8 9 10 11 13 14 15 16 17 19 20 21 22 23 24 25 27

Dessa maneira, estendemos repetidamente a sequência figura-figura. O $comportamento do comprimento é apenas uma maneira não trivial de economizar caracteres, aguardando que a sequência cresça para um comprimento nou mais e produzindo os nprimeiros valores quando eles param de mudar. Também não precisamos esperar muito: podemos obter 46336 termos em quatro aplicações do verbo interno.

A mesma função em k:

  • k2, 37 caracteres: {{x#y@&~_lin[y:1+!1+/y;1+\y]}[x]/2 4}
  • k4, 36 caracteres: {{x#y@&~(y:2+!1+/y)in\:1+\y}[x]/2 4}
algoritmshark
fonte
2

Java - 183 158

Foi o máximo que eu já joguei em qualquer coisa, e tenho orgulho disso! (Embora não esteja nem perto do topo dos gráficos (porque é Java))

Obrigado a Peter Taylor pelas sugestões

class f{public static void main(String[]a){int q=1,m=Byte.valueOf(a[0]),w=2,n[]=new int[m*m*2];for(n[q+=w]=1;m-->0;){System.out.println(w);for(;n[++w]>0;);}}}

Maior -

public class f {
    public static void main(String[] a) {
        int q = 1, m = Byte.valueOf(a[0]), w = 2, n[] = new int[m * m * 2];
        for (n[q += w] = 1; m-- > 0;) {
            System.out.println(w);
            for (; n[++w] > 0;)
                ;
        }
    }
}
Stretch Maniac
fonte
Esse loop for interno é ofuscado de maneira impressionante, mas acho que você pode salvar alguns bytes. Byte.valueOfsalva três e, como a pergunta não especifica o intervalo de entrada, acho que deve ser aceitável. Fora dos loops, mé usado apenas para inicializar n, o que k++<mpoderia ser m-->0, eliminando kcompletamente. int[] npode ser inicializado como int n[]e mesclado no inicializador anterior. nnunca possui valores diferentes de 1, então n[...]!=0poderia ser n[...]>0. O inicializador pode então se tornar a parte do primeiro forloop do inicializador .
Peter Peter Taylor
E se você se livrar ue usar ++w, não há necessidade de configurar n[q]ou n[w]. Há um erro, no qual você corre no final de nquando m==2, o que parece ser melhor corrigido ao inicializar n=new int[2*m*m], mas acho que o tamanho é de 157 bytes.
Peter Taylor
O que eu quis dizer sobre o inicializador se tornar a parte inicializadora do primeiro loop for estava for(int q=1,w=2,m=...,n[]=...;m-->0;){...salvando um ponto e vírgula.
Peter Taylor
1

Python 2 - 77 bytes


Código:

n=input();x=1;b=range(2,n*n)
while n:v=b.pop(0);x+=v;print v;b.remove(x);n-=1

Funciona da mesma forma que a solução do @ histocrat, exceto que a entrada vem do stdin.

matsjoyce
fonte
1

Python 2-68

R=[1]
s=0
n=input()
while n:s+=1+(s+1in R);R+=[R[-1]+s];print s;n-=1
Falko
fonte
0

Gelatina , 15 bytes

SƤŻ‘µṀ‘Rḟ
2dz¡ḣ

Experimente online!

Erro de memória na entrada de 6.

Como funciona

SƤŻ‘µṀ‘Rḟ  Aux. link (monad). Input: part of the desired sequence
SƤŻ‘       Sum of prefixes, then prepend a zero and increment
           This is a list of numbers to exclude from the next iteration
    µ      Re-focus on the above
     Ṁ‘Rḟ  Create range 1..Max + 1, then remove all elements of the above
           +1 is needed to progress from [2] to [2,4]

2dz¡ḣ  Main link (monad). Input: n, number of terms
2dz¡   Starting from 2, apply aux. link n times
    ḣ  Take n elements from the beginning

Versão mais eficiente, 16 bytes

SƤŻ‘µṀ‘Rḟḣ³
2ÇÐL

Experimente online!

Usa uma idéia de esta resposta J . Trunque no comprimento desejado a cada iteração e use o ponto de correção. Pensei em usar S(soma) em vez de Ṁ‘(max + 1), mas não posso garantir sua correção.

Bubbler
fonte
12 bytes .
Erik the Outgolfer