Calcola l'ennesimo termine della sequenza auto-descrittiva di Golomb


11

Ispirato alla domanda precedente .

La sequenza auto-descrittiva di Golomb g (n) è una sequenza in cui qualsiasi numero naturale nviene ripetuto all'interno della sequenza g (n) volte.

I primi numeri nella sequenza sono:

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

Puoi vedere che g (4) = 3 e che "4" viene ripetuto 3 volte nella sequenza.

Dato un input di n, output g(n).

Limitazioni: n <100000.

Vince il codice più piccolo.


Per gli approcci ingenui questo è lo stesso della domanda precedente, tranne per il fatto che utilizza nanziché 2 - n % 1. Hai qualche motivo per aspettarti che le risposte siano significativamente diverse?
Peter Taylor,

2
In Haskell, puoi usare questo:golomb=1:2:2:concat(zipWith replicate(drop 2 golomb)[3..])
FUZxxl

@PeterTaylor: non lo sapevo.
beary605,

Risposte:


5

GolfScript (31 caratteri)

~([1 2.]2{.2$=[1$)]*@\+\)}3$*;=

dimostrazione


Bello, ma hai davvero provato questo con n = 99999, e in tal caso, quanto tempo ci è voluto? (Quando l'ho provato, ha funzionato per un'ora prima di colpire il limite di memoria di 100 MiB che avevo impostato per esso e crash.)
Ilmari Karonen

@IlmariKaronen, no. La domanda non pone limiti alla memoria o all'efficienza temporale, quindi presumo che il limite sulla dimensione di input sia per quelle lingue che hanno ints a larghezza fissa.
Peter Taylor,

6

Gelatina , non competitiva

10 byte Questa risposta non è competitiva, poiché la sfida precede la creazione di Jelly.

’ßßạ¹ß‘µṖ¡

Questo utilizza la formula ricorsiva a (1) = 1, a (n + 1) = 1 + a (n + 1 - a (a (n))) dalla pagina OEIS.

Provalo online!

Come funziona

’ßßạ¹ß‘µṖ¡ Main link. Input: n

’          Decrement; yield n - 1.
 ßß        Recursively call the main link twice, with argument n - 1.
   ạ¹      Take the absolute difference of a(a(n - 1)) and n.
     ß     Recursively call the main link, with argument n - a(a(n - 1)).
      ‘    Increment the result, yielding 1 + a(n - a(a(n - 1))).
       µ   Combine the chain to the left into a single link.
        Ṗ  Pop [1, ..., n]. This yields [] iff n == 1.
         ¡ Execute the chain iff Ṗ returned a non-empty array.

4

PHP - 63 caratteri

function g($n){for(;++$i<=$n;){for(;++$j<=$i;){echo $i;}$j=0;}}

Veloce E corto.

Sembra che avessi in mente la sequenza sbagliata. Derp.

Questo è CORRETTO, veloce e breve.

function g($n){for(;++$i<$n;){echo round(1.201*pow($i,.618));}}

La precisione potrebbe subire oltre i 100.000 marchi richiesti, ma in effetti ho raggiunto il marchio.


3

PHP

Questa versione ricorsiva è più breve (60) ma computazionalmente inefficiente:

function g($n){return$n==1?1:1+g($n-g(g($n-1)));}echo g($n);

Questo è molto più veloce ma più lungo (78):

$a=[1,2,2];for($i=3;$i<$n;$i++)for($j=0;$j<$a[$i-1];$j++)$a[]=$i;echo$a[$n-1];

Molto più veloce, ma a 89 caratteri sarebbe:

$a=[1,2,2];for($i=3;!isset($a[$n-1]);$i++)for($j=0;$j<$a[$i-1];$j++)$a[]=$i;echo$a[$n-1];

Che è O (n)



3

Oasis , 7 byte (non concorrenti)

Codice:

n<aae>T

Provalo online!

Oasis è un linguaggio disegnato da Adnan specializzato in sequenze.

Attualmente, questa lingua può fare ricorsione e forma chiusa.

Alla Tfine è una scorciatoia per 10, che indica che a(0) = 0e a(1) = 1. Per aggiungere altri test, aggiungi semplicemente l'elenco alla fine.

n<aae>T
n<aae>10  expanded

       0  a(0) = 0
      1   a(1) = 1

n         push n (input)
 <        -1
  a       a(above)  [a is the sequence]
   a      a(above)
    e     a(n-above)
     >    +1

Ora abbiamo essenzialmente calcolato a(n-a(a(n-1))+1.


2

Perl, 48 caratteri

(@a=(@a,($,)x($a[$,++]||$,)))<$_?redo:say$,for<>

Input su stdin, output su stdout. Richiede Perl 5.10+ e l' -M5.010abilitazione della sayfunzione. Richiede circa O ( n 2 ) tempo a causa della manipolazione inefficiente dell'array, ma ancora abbastanza veloce da calcolare facilmente fino al 100.000 ° termine.


2

Julia - 28

In modo ricorsivo :

a(n)=n==1?1:1+a(n-a(a(n-1)))

Produzione:

[a(i) for i=1:20]'
1x20 Array{Int64,2}:
 1  2  2  3  3  4  4  4  5  5  5  6  6  6  6  7  7  7  7  8

2

Python - 64 caratteri

n=input()
g=[1,2,2]
for i in range(3,n):g+=[i]*g[i-1]
print g[n]

1
Bello. Non pensavo che farlo [i]*g[i-1]avrebbe fatto così mi sono chinato all'indietro per farlo in un altro modo; Pensavo che si sarebbe comportato più come moltiplicare una matrice per uno scalare per qualche motivo ...
Chucksmash,

1

Javascript, 93 caratteri

c=[,1],i=c.length;function g(n){for(i;i<n;i++) c[i]=g(i);return c[n]||(c[n]=1+g(n-g(g(n-1))))}

1

J, 43 caratteri

f=:3 :'<.@:+&0.5(p^2-p)*y^p-1[p=:(+%)/20$1'

Definisce una funzione usando l'espressione asintotica fornita nella pagina di Wikipedia.

   f 5
3
   f 20
8
   f 100000
1479

9 caratteri fastidiosi vengono usati solo arrotondando al numero intero più vicino.


1

Preludio , 69 55 54 byte

?1-(v  #1)-
1   0v ^(#    0 (1+0)#)!
    (#)  ^#1-(0)#

Se viene utilizzato un interprete conforme standard, questo accetta input e output come valori byte . Per utilizzare effettivamente i numeri decimali su STDIN / STDOUT, avrai bisogno dell'interprete Python con NUMERIC_OUTPUT = Truee un'opzione aggiuntivaNUMERIC_INPUT = True .

Spiegazione

Lo scheletro del programma è

?1-(    1 -
1                     )!

Leggiamo l'input Nsulla prima voce e lo diminuiamo per ottenere N-1. Inizializziamo anche la seconda voce a 1. Quindi eseguiamo il loop N-1una volta, ciascuna delle quali ottiene il valore successivo della sequenza sul secondo stack. Alla fine stampiamo ilN numero th.

L'idea del programma è di mettere ogni elemento della sequenza in una coda sulla terza voce e di decrementare il capo di quella coda in ogni iterazione. Quando la testa raggiunge 0, incrementiamo il valore della sequenza e lo rimuoviamo 0.

Ora il problema è che Prelude utilizza stack e non code. Quindi dobbiamo spostarci un po 'attorno a quello stack per usarlo come una coda.

v  #
0v ^
(#)

Questo copia il valore corrente della sequenza nella prima voce (come copia temporanea), inserisce 0a nella seconda voce (per contrassegnare la fine della coda). Quindi esegue un loop per spostare (e quindi invertire) il terzo stack sul secondo. Dopo il ciclo, mettiamo la copia del valore della sequenza corrente in cima al secondo stack (che è la coda della nostra coda).

 )
(#
 ^#1-

Sembra un po 'brutto, ma essenzialmente è un loop che sposta lo stack sulla terza voce. Dato che si )trova nella stessa colonna delle istruzioni di spostamento, la 0prima voce che inseriamo nella seconda voce finirà anche con la terza voce, quindi dobbiamo rimuoverla con un'altra #. Quindi decrementa la parte superiore della terza voce, ovvero il capo della coda.

Ora diventa un po 'fastidioso: vogliamo eseguire un po' di codice quando quel valore lo è 0, ma l'unica struttura di controllo (il ciclo) di Prelude risponde solo a valori diversi da zero.

 0 (1+0)#
(0)#

Nota che la parte superiore della seconda voce è veritiera (poiché la sequenza Golomb non contiene alcuna 0s). Quindi il carico di lavoro entra in quella voce (quest'ultima coppia di parentesi). Dobbiamo solo impedire che ciò accada se il capo della coda non è 0ancora. Quindi per prima cosa abbiamo un "loop" sulla terza voce che spinge a 0sulla seconda voce se la testa della coda è ancora diversa da zero. Abbiamo anche inserito 0la terza voce per uscire immediatamente dal loop. La #terza voce rimuove quindi quella 0, o rimuove la testa della coda se quella era già pari a zero. Ora quel secondo ciclo viene inserito solo se il capo della coda era zero (e il0sulla seconda voce non è mai stato premuto). In tal caso incrementiamo il valore corrente della sequenza e premiamo a 0per uscire dal loop. Infine, ci sarà sempre uno 0in cima allo stack, che dobbiamo scartare.

Ti ho detto che la negazione logica è fastidiosa in Prelude ...


1

Mathematica, 27 byte

f@1=1;f@n_:=1+f[n-f@f[n-1]]

Un'altra soluzione ricorsiva.


1

CJam, 14 byte

CJam è molto più giovane di questa sfida, quindi questa risposta non è ammissibile per il segno di spunta verde. Tuttavia, è abbastanza raro che tu lo usi jbene, quindi volevo pubblicarlo comunque.

l~2,{_(jj-j)}j

Provalo qui.

Spiegazione

jè fondamentalmente "l'operatore di ricorsione memorizzato". Ci vuole un numero intero N, un array e un blocco F. La matrice viene utilizzata per inizializzare la memoisation: l'elemento all'indice iverrà restituito per F(i). jquindi calcola F(N), cercandolo, oppure eseguendo il blocco (con nnello stack) se il valore non è stato ancora memorizzato. La caratteristica veramente nifty è che all'interno del blocco, jrichiede solo un numero intero i, e chiama F(i)ricorsivamente. Quindi ecco il codice:

l~             "Read and eval input.";
  2,           "Push a 2-range onto the stack, i.e. [0 1]. The first value is irrelevant
                but the second value is the base case of the recursion.";
    {       }j "Compute F(N).";
     _(        "Duplicate i and decrement to i-1.";
       jj      "Compute F(F(i-1)).";
         -     "Subtract from i.";
          j    "Compute F(n-F(F(i-1))).";
           )   "Increment the result.";

1

J, 16 byte

    <:{1($1+I.)^:[~]

    (<:{1($1+I.)^:[~]) every 1+i.20  NB. results for inputs 1..20
1 2 2 3 3 4 4 4 5 5 5 6 6 6 6 7 7 7 7 8

Questa soluzione è fortemente basata sulla soluzione di algoritmo condiviso a un problema simile. Puoi trovare alcune spiegazioni su questo metodo lì.

J, 33 byte

In questo approccio ho creato una sequenza h(k)con i valori dei primi indici in icui è g(i)=kcosì h = 1 2 4 6 9 12 16.... Possiamo ottenere h(k)abbastanza semplicemente h(1..k-1)dall'espressione in ({:+1+[:+/#<:])cui si trova l'input h(1..k-1).

Il calcolo dell'output da hè semplice.h ([:+/]>:[) input

[:+/]>:1 2(,{:+1+[:+/#<:])@]^:[~]

1

Brachylog , 13 byte (non concorrenti)

1|-₁↰↰:?-ṅ↰+₁

Provalo online!

Spiegazione

1                Input = 1 = Output
 |               Or
  -₁↰            a(Input - 1)
     ↰           a(a(Input - 1))
      :?-ṅ       Input - a(a(Input - 1))
          ↰      a(Input - a(a(Input - 1))
           +₁    1 + a(Input - a(a(Input -1))

0

Python - 76 caratteri

n=20;g=[1,2,2];[[g.append(i)for j in range(g[i-1])]for i in range(3,n)];g[n]

Questo in realtà riempie l'elenco con un sacco di Nones. Sembra essere la quantità "corretta" di Nones tho :)
daniero

1
@Daniero, sì, è una specie di codice strano. Ho dovuto eseguirlo un paio di volte per convincermi che funzionava davvero. Riempie la comprensione dell'elenco con un gruppo di Nones poiché list.append () restituisce il Nonetipo. Ho appena usato la comprensione dell'elenco nidificato per ottenere un ciclo nidificato. L'unico scopo della comprensione dell'elenco qui è far sì che il codice
esegua

Salva due personaggi se avessi fatto i tradizionali cicli nidificati :)
Chucksmash

Sfortunatamente sembra che tu stia codificando l'input, cosa che non consentiamo, e supponendo un ambiente REPL, che lo renderebbe un frammento. Per impostazione predefinita , tutti gli invii devono essere programmi o funzioni completi che utilizzano uno dei nostri metodi I / O predefiniti anziché snippet. Fatemi sapere se avete domande.
Alex A.

@AlexA. Fare un po 'di archeologia?
Chucksmash,

0

JavaScript - 48 caratteri

for(g=[,i=j=k=1,2];i<1e5;k=--k?k:g[++j])g[i++]=j

Crea una matrice gcon 1 indice contenente i valori della sequenza.

Modifica - JavaScript - 46 caratteri

v=[,1];for(x=2;x<1e5;)v[x]=1+v[x-v[v[x++-1]]]

Crea una matrice vcon 1 indice contenente i valori della sequenza.

Modifica 2 - Caratteri ECMAScript 6 - 27

g=x=>x-1?1+g(x-g(g(x-1))):1

I primi due sono ragionevolmente veloci - il terzo è molto lento


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.