Sequenza H. di Hofstadter


15

Definizione

  • a(0) = 0
  • a(n) = n-a(a(a(n-1))) per intero n > 0

Compito

Dato intero non negativo n, output a(n).

Casi test

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

Riferimenti


Sfide correlate alle sequenze di Hofstadter: 1 , 2 , 3
Martin Ender,

4
E penso ancora che dovresti fare riferimento a GEB ...
Martin Ender il

1
In che modo la teoria dei numeri è rilevante qui?
Flawr

1
@flawr facepalm Lasciami riprovare: Gödel, Escher, Bach: An Eternal Golden Braid
Stig Hemmer

1
@StigHemmer In realtà facepalm ha le sue Emoji ora: 🤦
Tobias Kienzler,

Risposte:


20

Haskell, 23 22 byte

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

Usa semplicemente la definizione della sequenza. f(f$f$n-1)è equivalente a f (f (f (n-1))).

Test:

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]

Grazie ad Anders Kaseorg per un byte!


(f$f$f$n-1)= f(f$f$n-1)salva un byte.
Anders Kaseorg,

9

Gelatina , 8 byte

’ßßßạµṠ¡

Provalo online! oppure verifica i casi di test più piccoli .

Come funziona

’ßßßạµṠ¡  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.

9
Il parser Jelly può anche gestire programmi di dimensioni superiori a 10 byte?
steenbergh,

9

Mathematica, 20 byte

Il conteggio dei byte presuppone la codifica ISO 8859-1 (o compatibile) e $CharacterEncodingimpostato su un valore corrispondente, come l'impostazione predefinita di Windows WindowsANSI.

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

Questo definisce un operatore unario ±.


Spiegheresti cosa fa ± o come funziona? A proposito, congratulazioni per 100k.
DavidC

1
@DavidC Grazie. :) È solo un operatore integrato che è una scorciatoia per la funzione non utilizzata PlusMinus. Vedi questo post per i dettagli.
Martin Ender,

1
Molto interessante. Dispensa con @o [ ]anche.
David C

9

J, 14 12 byte

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

Salvato 2 byte grazie a @ Leaky Nun .

Calcola il risultato chiamando se stesso in modo ricorsivo quando n > 0 tre volte su n -1 e sottraendo quel risultato da n . Esiste una situazione diversa per il caso base quando n = 0. Qui calcola n - n che equivale a 0.

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

Provalo qui.

Spiegazione

-$:^: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

Non penso che siano necessarie le parentesi.
Leaky Nun,

6

Julia, 16 byte

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

Provalo online!

Come funziona

Ridefiniamo l'operatore unario ! per i nostri scopi.

Se n = 0 , il confronto n>0restituisce false e così fa! .

Altrimenti, il codice dopo &&viene eseguito. ~-nè equivalente al (n-1)complemento a due, !!!chiama ricorsivamente !tre volte su n - 1 e il valore risultante viene sottratto da n .


Ti dispiace aggiungere una spiegazione? Non ho idea di cosa stia succedendo -!!~-..
Downgoat,

1
Nulla di bello. !è semplicemente il nome della funzione.
Dennis,

5

Python, 31 byte

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

Il limite di ricorsione e i vincoli di tempo rendono la funzione di cui sopra poco pratica, ma in teoria dovrebbe funzionare (e funziona per la piccola n).


4

JavaScript (ES6), 52 byte

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

Avrei potuto annoiare e scrivere la versione ricorsiva, ma questa versione è molto più veloce (si occupa facilmente dell'ultimo test case) e lo usa anche, reducequindi è un vantaggio!




3

R, 42 41 byte

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

Uso:

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

Questo approccio ricorsivo non si adatta bene a valori più grandi di nperò.


Dovresti riuscire a perdere un byte (e un numero di errori con input errati) se cambi la tua condizione in n<1. Essendo una sequenza, è comunque definita solo per interi non negativi.
user5957401

a=function(n)"if"(n,n-a(a(a(n-1))),0)funzionerà per diversi byte.
Giuseppe,

3

Oasi , 6 byte

Codice:

nbaa-0

Versione estesa:

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

Codice:

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

Provalo online!


2

Sesos , 58 55 byte

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..

Gestisce input fino a 400 ragionevolmente bene, ma il tempo di esecuzione aumenta notevolmente dopo quel punto.

Provalo online!Controlla il debug per vedere il codice SBIN generato.

Assemblaggio Sesos

Il file binario sopra è stato generato assemblando il seguente codice 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

2

LISP, 61 byte

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

Probabilmente non è la soluzione ottimale, ma funziona.


1

Java 7, 42 byte

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

Casi non testati e test:

Provalo qui.

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));
  }
}

Produzione:

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..)

1

Rubino, 27 byte

L'ovvia implementazione.

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

Questa è una risposta più lunga e più veloce che memorizza nella cache le voci precedenti nella sequenza. Entrambe le risposte funzionano solo per le versioni successive alla 1.9, com'era quando ->, il stabby lambda, fu presentato a Ruby.

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


1

Golfscript, 26 25 byte

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

Provalo online!

A livello locale 10000richiede meno di mezzo secondo.


1

C, 35 32 byte

Salvato 3 byte grazie a @PeterTaylor!

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

Provalo su Ideone!


2
In C puoi usare un intero direttamente come condizionale, dando un salvataggio di tre byte:a(n){return n?n-a(a(a(n-1))):0;}
Peter Taylor

1
@betseg - Anche tu hai un :codice errato . Dovresti eliminare quello dopo ?.
owacoder,

1

Javascript ES6, 22 byte

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

Sarò noioso e farò la versione ricorsiva: P


1

VBA, 69 byte

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

Funziona in un batter d'occhio sul set di test, rallenta leggermente sopra n = 1000000, si imbatte in un muro di memoria leggermente sopra n = 25 milioni.


1

Pyth, 10 byte

L-WbbyFtb3

Definisce una funzione y. Provalo online: dimostrazione

Questo utilizza una nuova funzionalità relativa di Pyth. È possibile applicare una funzione più volte utilizzando la sintassi pieghevole. In realtà non salva alcun byte, l'ho usato solo a scopo dimostrativo.

Spiegazione:

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

1

Acero, 28 26 byte

`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

1

dc, 34 byte

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

L'input è preso dalla cima dello stack. Questo deve essere l'unico oggetto nella pila, poiché la profondità della pila viene utilizzata come contatore. Esempio di utilizzo:

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

Questa è un'implementazione abbastanza semplice della definizione della sequenza:

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)

Comunque, è iniziato in modo semplice ... poi è successo il golf.



1

C ++ (MSVC, principalmente)

Versione normale: 40 byte

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

Versione meta-programmazione modello: 130 byte

#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;}};

Utilizzo:

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

La versione del modello è il codice più veloce, poiché non c'è niente di più veloce che spostare un valore in un registro => con l'ottimizzazione, H<20>::a()compilare come:

mov esi, 14

Per 10000, la versione ricorsiva si arresta in modo anomalo a causa di un errore di overflow dello stack e la versione del modello si arresta in modo anomalo in fase di compilazione a causa della profondità dell'istanza del modello. GCC va a 900 (614)


Penso che non sia necessario lo spazio tra Ce {nella versione meta-programmazione del modello
Zacharý,

@ Zacharý MSVC si rifiuta di compilare senza quello spazio
HatsuPointerKun

Ahh, vedo ora perché sembra che ciò accada
Zacharý

@ Zacharý Dipende dal tipo di macro. Se ha dei parametri, posso rimuovere lo spazio, ma qui no
HatsuPointerKun


1

APL (Dyalog Unicode) , 18 17 byte

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

Provalo online!

Sorprendentemente, non esiste una risposta APL a questa sfida. Questa è un'implementazione letterale della funzione nel PO.

TIO scade per n>90.

Salvataggio di un byte grazie a @ Zacharý.


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


0

PowerShell v2 +, 56 byte

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

L'equivalente di PowerShell di una lambda per formare la definizione ricorsiva. Eseguire tramite l' &operatore di chiamata, ad es &$a(5). Ci vuole molto tempo per eseguire - anche50 richiede sulla mia macchina (un recente i5 con 8 GB di RAM) richiede circa 90 secondi.

Soluzione iterativa più rapida, 59 byte

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

Più a lungo solo perché dobbiamo tenere conto dell'input 0(quello è *!!$nalla fine). Altrimenti costruiamo solo in modo iterativo l'array $n, aggiungendo ogni volta un nuovo elemento e producendo l'ultimo alla fine $o[-1]. Super-veloce: il calcolo 10000sulla mia macchina richiede circa 5 secondi.


0

> <> , 55 + 2 = 57 byte

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

Si prevede che l'input sia presente nello stack all'avvio del programma, quindi +2 byte per il -vflag. Provalo online!

Questo è molto lento, in quanto utilizza la ricorsione per calcolare il risultato. L'uso di TIO h(50)richiede più di un minuto. Restituisce i risultati corretti <= 30, quindi sono sicuro che funzionerebbe h(10000), non l'ho eseguito per scoprirlo!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.