Sequência H de Hofstadter

15

Definição

  • a(0) = 0
  • a(n) = n-a(a(a(n-1))) para inteiro n > 0

Tarefa

Dado inteiro não negativo n, saída a(n).

Casos de teste

n     a(n)
0     0
1     1
2     1
3     2
4     3
5     4
6     4
7     5
8     5
9     6
10    7
11    7
12    8
13    9
14    10
15    10
16    11
17    12
18    13
19    13
20    14
10000 6823

Referências

Freira Furada
fonte
Desafios relacionados às seqüências de Hofstadter: 1 , 2 , 3
Martin Ender
4
E eu ainda acho que você deve fazer referência GEB ...
Martin Ender
1
Como a teoria dos números é relevante aqui?
flawr
1
@flawr facepalm Deixe-me tentar de novo: Gödel, Escher, Bach: An Eternal Golden Braid
Stig Hemmer
1
@StigHemmer Na verdade facepalm tem seu próprio Emoji agora: 🤦
Tobias KIENZLER

Respostas:

20

Haskell, 23 22 bytes

f 0=0
f n=n-f(f$f$n-1)

Simplesmente usa a definição da sequência. f(f$f$n-1)é equivalente a f (f (f (n-1))).

Teste:

main = putStrLn . show $ map f [0..20]
-- => [0,1,1,2,3,4,4,5,5,6,7,7,8,9,10,10,11,12,13,13,14]

Obrigado a Anders Kaseorg por um byte!

Maçaneta da porta
fonte
(f$f$f$n-1)= f(f$f$n-1)salva um byte.
Anders Kaseorg
9

Geléia , 8 bytes

’ßßßạµṠ¡

Experimente online! ou verifique os casos de teste menores .

Como funciona

’ßßßạµṠ¡  Main link. Argument: n

     µṠ¡  Execute the preceding chain sign(n) times.
’         Decrement n, yielding n - 1.
 ßßß      Recursively call the main link thrice.
    ạ     Take the absolute difference of n and the result.
Dennis
fonte
9
O analisador Jelly pode até lidar com programas maiores que 10 bytes?
213166 #
9

Mathematica, 20 bytes

A contagem de bytes assume a codificação ISO 8859-1 (ou compatível) e $CharacterEncodingdefinida como um valor correspondente, como o padrão do Windows WindowsANSI.

±0=0
±n_:=n-±±±(n-1)

Isso define um operador unário ±.

Martin Ender
fonte
Você explicaria o que ± faz ou como funciona? Btw, parabéns por 100k.
DavidC
1
@DavidC Thanks. :) É apenas um operador interno, que é uma abreviação para a função não utilizada PlusMinus. Veja este post para detalhes.
Martin Ender
1
Muito interessante. Dispensa com o @ou [ ]também.
DavidC
9

J, 14 12 bytes

-$:^:3@<:^:*

Economizou 2 bytes graças a @ Leaky Nun .

Calcula o resultado chamando-se recursivamente quando n > 0 três vezes em n -1 e subtraindo esse resultado de n . Existe uma situação diferente para o caso base quando n = 0. Lá ele calcula n - n que é igual a 0.

a(n) = n - n = 0           if n = 0
       n - a(a(a(n-1)))    if n > 0

Experimente aqui.

Explicação

-$:^:3@<:^:*  Input: n
           *  Get the sign of n (n = 0 => 0, n > 0 => 1)
         ^:   Execute that many times
                (0 times means it will just be an identity function)
       <:       Decrement n
 $:             Call itself recursively
   ^:3          three times
      @         on n-1
-             Subtract that result from n and return
milhas
fonte
Não acho que os parênteses sejam necessários.
Freira vazada
6

Julia, 16 bytes

!n=n>0&&n-!!!~-n

Experimente online!

Como funciona

Redefinimos o operador unário !para nossos propósitos.

Se n = 0 , a comparação n>0retorna false e o mesmo acontece !.

Caso contrário, o código depois &&será executado. ~-né equivalente a (n-1)no complemento de dois, !!!chama recursivamente !três vezes em n - 1 e o valor resultante é subtraído de n .

Dennis
fonte
Se importa de adicionar uma explicação? Não faço ideia do que está acontecendo -!!~-.
Downgoat
1
Nada chique. !é simplesmente o nome da função.
Dennis
5

Python, 31 bytes

a=lambda n:n and n-a(a(a(n-1)))

Limites de recursão e restrições de tempo tornam a função acima impraticável, mas em teoria deve funcionar (e funciona para pequenos n).

orlp
fonte
4

JavaScript (ES6), 52 bytes

n=>[0,...Array(n)].reduce((p,_,i,a)=>a[i]=i-a[a[p]])

Eu poderia ter sido chato e escrito a versão recursiva, mas essa versão é muito mais rápida (é fácil lidar com o último caso de teste) e também usa, reduceentão isso é uma vantagem!

Neil
fonte
4

Retina , 49 43 bytes

.+
$*1:
{`^1(1*):
$1:::-1$1
}`^:*(1*)-\1

1

Experimente online!

Martin Ender
fonte
3

CJam, 13 12 bytes

Agradecemos a Dennis por economizar 1 byte.

ri0{_(jjj-}j

Teste aqui.

Martin Ender
fonte
Isso funciona para valores surpreendentemente altos. Eu acho que você não precisa do a.
Dennis
@ Dennis Oh, é bom saber, obrigado.
Martin Ender
3

R, 42 bytes

a=function(n)ifelse(n<1,0,n-a(a(a(n-1))))

Uso:

> a(1)
1
> a(10)
7

Essa abordagem recursiva não se adapta bem a valores maiores n.

DSkoog
fonte
Você poderá perder um byte (e vários erros com entradas incorretas) se alterar sua condição para n<1. Como é uma sequência, é realmente definido apenas para números inteiros não negativos de qualquer maneira.
user5957401
a=function(n)"if"(n,n-a(a(a(n-1))),0)funcionará por vários bytes desativados.
21717 Giuseppe
3

Oásis , 6 bytes

Código:

nbaa-0

Versão expandida:

a(n) = nbaa-
a(0) = 0

Código:

n      # Push n
 b     # Calculate a(n - 1)
  a    # Calculate a(a(n - 1))
   a   # Calculate a(a(a(n - 1)))
    -  # Subtract a(a(a(n - 1))) from n

Experimente online!

Adnan
fonte
2

Sesos , 58 55 bytes

0000000: 16e0d7 bdcdf8 8cdf1b e6cfbb 840d3f bf659b 38e187  ..............?.e.8..
0000015: f8639b 39dc37 fc893f 666c05 7e7ed9 b88b3f ae0d3f  .c.9.7..?fl.~~...?..?
000002a: 676ed8 bd9940 7fdc3b 36619e f1                    gn...@..;6a..

Lida com entradas até 400 razoavelmente bem, mas o tempo de execução aumenta drasticamente após esse ponto.

Experimente online! Marque Debug para ver o código SBIN gerado.

Montagem Sesos

O arquivo binário acima foi gerado pela montagem do seguinte código SASM.

set numin, set numout

get
jmp
    jmp
        rwd 3, add 1, rwd 1, add 1, fwd 4, sub 1
    jnz
    rwd 3, sub 1
jnz
rwd 3, add 1, fwd 2
jmp
    rwd 1, sub 1, fwd 3, sub 1, fwd 2, add 3
    jmp
        rwd 2
        jmp
            rwd 3
        jnz
        fwd 6, get, rwd 4, sub 1
        jmp
            fwd 1, sub 1
            jmp
                rwd 3
            jnz
            sub 1
            jmp
                fwd 3
            jnz
            rwd 4, sub 1
        jnz
        fwd 1
        jmp
            rwd 1, add 1, fwd 1, add 1
        jnz
        sub 1, fwd 3, sub 1
        jmp
            fwd 3
        jnz
        rwd 1, sub 1
    jnz
    rwd 2, get
    nop
        rwd 3
    jnz
    fwd 3, get, rwd 2
    jmp
        fwd 2, add 1
        jmp
            fwd 3
        jnz
        rwd 1, add 1, rwd 2
        jmp
            rwd 3
        jnz
        fwd 1, sub 1
    jnz
    fwd 2
    jmp
        rwd 2, add 1, fwd 2, sub 1
    jnz
    nop
        get, fwd 3
    jnz
    rwd 1, add 1, fwd 2
jnz
rwd 2, sub 1
jmp
    rwd 1, sub 1, fwd 1, sub 1
jnz
rwd 1, put
Dennis
fonte
2

LISP, 61 bytes

(defun H(N)(if(= N 0)(return-from H 0)(- N(H(H(H(- N 1)))))))

Provavelmente não é a solução ideal, mas funciona.

Esthete
fonte
1

Java 7, 42 bytes

int c(int n){return n>0?n-c(c(c(n-1))):0;}

Casos não testados e de teste:

Experimente aqui.

class Main{
  static int c(int n){
    return n > 0
              ? n - c(c(c(n-1)))
              : 0;
  }

  public static void main(String[] a){
    for(int i = 0; i < 21; i++){
      System.out.println(i + ": " + c(i));
    }
    System.out.println("1000: " + c(1000));
  }
}

Resultado:

0: 0
1: 1
2: 1
3: 2
4: 3
5: 4
6: 4
7: 5
8: 5
9: 6
10: 7
11: 7
12: 8
13: 9
14: 10
15: 10
16: 11
17: 12
18: 13
19: 13
20: 14
 (last case takes too long..)
Kevin Cruijssen
fonte
1

Ruby, 27 bytes

A implementação óbvia.

a=->n{n<1?0:n-a[a[a[n-1]]]}

Essa é uma resposta mais longa e rápida que armazena em cache as entradas anteriores na sequência. Ambas as respostas funcionam apenas para versões posteriores a 1.9, como foi quando ->o lambda stabby foi introduzido no Ruby.

->n{r=[0];i=0;(i+=1;r<<i-r[r[r[i-1]]])while i<n;r[n]}
Sherlock9
fonte
1

C #, 35 bytes

int a(int n)=>n>0?n-a(a(a(n-1))):0;
TheLethalCoder
fonte
1

Golfscript, 26 25 bytes

~ [0] {...., (=== \., @ - +} @ *) \;
~ [0] {...) \; == \., @ - +} @ *) \;

Experimente online!

Localmente 10000leva menos de meio segundo.

Freira Furada
fonte
1

C, 35 32 bytes

Economizou 3 bytes graças a @PeterTaylor!

a(n){return n?n-a(a(a(n-1))):0;}

Experimente no Ideone!

betseg
fonte
2
Em C você pode usar um inteiro diretamente como uma condicional, dando uma poupança de três bytes:a(n){return n?n-a(a(a(n-1))):0;}
Peter Taylor
1
@betseg - Você também tem um erro :no seu código. Você deve tirar o depois ?.
Owacoder 02/08
1

Javascript ES6, 22 bytes

a=n=>n&&n-a(a(a(n-1)))

Vou ser chato e fazer a versão recursiva: P

Mama Fun Roll
fonte
1

VBA, 69 bytes

Function H(N):ReDim G(N):For j=1To N:G(j)=j-G(G(G(j-1))):Next:H=G(N)

Funciona em um piscar de olhos no conjunto de testes, diminui um pouco acima de n = 1000000, colide com uma parede de memória um pouco acima de n = 25 milhões.

Joffan
fonte
1

Pitão, 10 bytes

L-WbbyFtb3

Define uma função y. Experimente online: Demonstração

Isso usa um novo recurso relativo do Pyth. Você pode aplicar uma função várias vezes usando a sintaxe da dobra. Na verdade, ele não salva bytes, usei-o apenas para fins de demonstração.

Explicação:

L-WbbyFtb3
L            define function y(b), that returns:
    b           b
 -Wb            and subtract the following if b>0
     yF  3      y applied three times to
       tb       b - 1
Jakube
fonte
1

Bordo, 28 26 bytes

`if`(n=0,0,n-a(a(a(n-1))))

Uso:

> a:=n->ifelse(n=0,0,n-a(a(a(n-1))));
> seq(a(i),i=0..10);
0, 1, 1, 2, 3, 4, 4, 5, 5, 6, 7
DSkoog
fonte
1

dc, 34 bytes

dsn[zdddd1-;a;a;a-r:aln!=L]dsLx;ap

A entrada é retirada da parte superior da pilha. Esse deve ser o único item da pilha, porque a profundidade da pilha é usada como um contador. Exemplo de uso:

$ dc
10000dsn[zdddd1-;a;a;a-r:aln!=L]dsLx;ap

Esta é uma implementação bastante direta da definição de sequência:

dsn               # Store n as `n', and keep a copy as a depth buffer (see below)
[                 # Open loop definition
 z                # Push stack depth i for i-th term
 dddd             # Duplicate stack depth four times, for a total of five copies
 1-               # Get i-1 for use as index to previous term
                  #   Note that if we hadn't duplicated n above, or left something else
                  #   on the stack, 0-1 would be -1, which is not a valid array index
 ;a;a;a           # Fetch a(a(a(i-1)))
 -                # Calculate i-a(a(a(i-1)))
 r                # Arrange stack to store i-th term: TOS |  i  (i-a(a(a(i-1))))
 :a               # Store i-th term in array `a'
 ln!=L            # Load n. If n!=i, we're not done calculating terms yet, so execute loop
]                 # Close loop definition. Note that we started with five copies of i:
                  #   i-1 was used to get last term
                  #   i-a(...) was used to calculate current term
                  #   ... i :a was used to store current term
                  #   i ln !=L was used to check loop exit condition
                  # One copy of i is left on the stack to increment counter
dsLx              # Duplicate loop macro, store it, and execute copy
;a                # Last i stored on stack from loop will equal n, so use this to get a(n)
p                 # Print a(n)

De qualquer forma, tudo começou bem ... então o golfe aconteceu.

Joe
fonte
1

C ++ (MSVC, principalmente)

Versão normal: 40 bytes

int a(int n){return n?n-a(a(a(n-1))):0;}

Versão da meta-programação do modelo: 130 bytes

#define C {constexpr static int a(){return
template<int N>struct H C N-H<H<H<N-1>::a()>::a()>::a();}};template<>struct H<0>C 0;}};

Uso:

std::cout << a(20) << '\n';       // Normal version
std::cout << H<20>::a() << '\n';  // Template version

A versão do modelo é o código mais rápido, pois não há nada mais rápido do que mover um valor para um registrador => com otimização, H<20>::a()compile como:

mov esi, 14

Para 10000, a versão recursiva falha devido a um erro de estouro de pilha e a versão do modelo falha no tempo de compilação devido à profundidade da instanciação do modelo. O GCC vai para 900 (614)

HatsuPointerKun
fonte
Eu acho que você não precisa do espaço entre Ce {na versão do modelo meta de programação
Zachary
@ Zachary MSVC se recusa a compilar sem que o espaço
HatsuPointerKun
Ahh, eu vejo agora por que parece continuar acontecendo
Zachary
@ Zacharý Depende do tipo de macro. Se ele tem parâmetros, então eu posso remover o espaço, mas aqui isso não acontece
HatsuPointerKun
1

APL (Dyalog Unicode), 18 17 bytes

{⍵=0:0⋄⍵-∇⍣3⊢⍵-1}

Try it online!

Surprisingly, there's no APL answer to this challenge. This is a literal implementation of the function in the OP.

TIO times out for n>90.

Saved a byte thanks to @Zacharý.

J. Sallé
fonte
1
{⍵=0:0⋄⍵-∇⍣3⊢⍵-1}
Zacharý
0

Python 3, 72 bytes

def f(n):
    a=[0];i=0
    while n:i+=1;a+=[i-a[a[a[i-i]]]];n-=1
    return a[i]

Ideone it!

Leaky Nun
fonte
0

PowerShell v2+, 56 bytes

$a={$n=$args[0];if($n){$n-(&$a(&$a(&$a($n-1))))}else{0}}

The PowerShell equivalent of a lambda to form the recursive definition. Execute it via the & call operator, e.g. &$a(5). Takes a long time to execute -- even 50 on my machine (a recent i5 with 8GB RAM) takes around 90 seconds.

Faster iterative solution, 59 bytes

param($n)$o=,0;1..$n|%{$o+=$_-$o[$o[$o[$_-1]]]};$o[-1]*!!$n

Longer only because we need to account for input 0 (that's the *!!$n at the end). Otherwise we just iteratively construct the array up to $n, adding a new element each time, and output the last one at the end $o[-1]. Super-speedy -- calculating 10000 on my machine takes about 5 seconds.

AdmBorkBork
fonte
0

><>, 55+2 = 57 bytes

^~n;
.~-]{:0$
v>1-}32[
v/  /:1-32[
>$:?/$~]{:0$.
/30@2[

The input is expected to be present on the stack at program start, so +2 bytes for the -v flag. Try it online!

This is hecka slow, as it uses recursion to calculate the result. Using TIO, h(50) takes over a minute. It returns the correct results <= 30, so I'm confident it would work for h(10000), I just haven't run it to find out!

Sok
fonte