Contare avanti e indietro, quindi raddoppiare


24

Contiamo...

Conta fino a 2 e torna a 1
Conta fino a 4 e torna a 1
Conta fino a 6 e torna a 1
... ok hai capito ...

metti insieme tutti questi e otterrai la seguente sequenza

 {1,2,1,2,3,4,3,2,1,2,3,4,5,6,5,4,3,2,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1,2,3...}

Sfida
Dato un numero intero n>0per 1-indicizzato (o n>=0per 0-indicizzato), genera l'ennesimo termine di questa sequenza

Casi test

Input->Output  

1->1  
68->6  
668->20  
6667->63  
10000->84

Regole

il tuo programma deve essere in grado di calcolare soluzioni fino a n = 10000 in meno di un minuto

Questo è , quindi vince il codice più corto in byte!


2
Chi decide cosa richiede un minuto? Una macchina Turing ottimale per il tempo costruita da lego richiederebbe davvero molto tempo, mentre la stessa macchina Turing simulata, diciamo, in C, presumibilmente richiederebbe secondi o minuti, a seconda del processore su cui gira. Pertanto, se invio la suddetta descrizione della macchina di Turing, è valida?
Arthur,

2
@Arthur Penso che tu possa capire perché ho fatto questa restrizione ... Non volevo che un algoritmo impiegasse "per sempre" per trovare n = 10000 producendo un enorme elenco. La maggior parte delle persone qui ha dato risposte brillanti che trovano milioni in secondi.

4
@BillSteihn Penso che la restrizione non sia necessaria.
Erik the Outgolfer,

2
@EriktheOutgolfer gode delle risposte al golf può essere complicato ... senza la restrizione una risposta che produce 10.000 tuple [1,2 ... 2n..2,1] sarebbe valida. La restrizione è solo per le risposte come questa. t vedere dov'è il problema. Voglio solo che la tua risposta trovi tutti i casi di test in un ragionevole lasso di tempo.

3
@StraklSeth Il consenso generale qui è che dovrebbe funzionare in teoria, non necessariamente in pratica.
Erik the Outgolfer,

Risposte:


16

JavaScript (ES7),  59 ... 44  43 byte

Salvato 1 byte grazie a Titus

Input previsto: 1 indicizzato.

n=>(n-=(r=(~-n/2)**.5|0)*r*2)<++r*2?n:r*4-n

Inizialmente ispirato a una formula per A004738 , che è una sequenza simile. Ma ho finito per riscriverlo interamente.

Casi test

Come?

La sequenza può essere disposta come un triangolo, con la parte sinistra in ordine crescente e la parte destra in ordine decrescente.

Di seguito sono le prime 4 righe, contenenti i primi 32 termini:

            1 | 2
        1 2 3 | 4 3 2
    1 2 3 4 5 | 6 5 4 3 2
1 2 3 4 5 6 7 | 8 7 6 5 4 3 2

Ora, introduciamo alcune variabili:

 row  | range   | ascending part              | descending part
 r    | x to y  | 1, 2, ..., i                | 4(r+1)-(i+1), 4(r+1)-(i+2), ...
------+---------+-----------------------------+-----------------------------------------
  0   |  1 -  2 |                           1 | 4-2
  1   |  3 -  8 |                   1   2   3 | 8-4  8-5  8-6
  2   |  9 - 18 |           1   2   3   4   5 | 12-6 12-7 12-8  12-9  12-10
  3   | 19 - 32 |   1   2   3   4   5   6   7 | 16-8 16-9 16-10 16-11 16-12 16-13 16-14

Iniziamo con 2 elementi in alto e aggiungiamo 4 elementi in ogni nuova riga. Pertanto, il numero di elementi sul 0-indicizzato riga r può essere espresso come:

a(r) = 4r + 2

La posizione di partenza 1-indicizzato x della riga r è data dalla somma di tutti i termini precedenti in questa serie aritmetica più uno, che porta a:

x(r) = r * (2 + a(r - 1)) / 2 + 1
     = r * (2 + 4(r - 1) + 2) / 2 + 1
     = 2r² + 1

Reciprocamente, data una posizione 1-indicizzata n nella sequenza, la riga corrispondente si trova con:

r(n) = floor(sqrt((n - 1) / 2))

o come codice JS:

r = (~-n / 2) ** 0.5 | 0

Una volta che conosciamo r (n) , sottraggiamo la posizione iniziale x (r) meno una da n :

n -= r * r * 2

Confrontiamo n con a (r) / 2 + 1 = 2r + 2 per capire se siamo nella parte crescente o nella parte discendente:

n < ++r * 2 ?

Se questa espressione è vera, restituiamo n . Altrimenti, restituiamo 4 (r + 1) - n . Ma poiché r era già incrementato nell'ultima istruzione, questo è semplificato come:

n : r * 4 - n

1
Ok, penso di aver capito. La lunghezza di ciascuna parte su-giù è 2,6,10,14 ... quindi la somma cresce con il quadrato del conteggio delle righe, quindi il sqrt. Molto bella!
JollyJoker il

7

Haskell , 37 byte

(!!)$do k<-[1,3..];[1..k]++[k+1,k..2]

Provalo online!

Zero indicizzati. Genera l'elenco e gli indici in esso. Grazie a Ørjan Johansen per aver salvato 2 byte!


Haskell , 38 byte

(!!)[min(k-r)r|k<-[0,4..],r<-[1..k-2]]

Provalo online!

Zero indicizzati. Genera l'elenco e gli indici in esso.


Haskell , 39 byte

n%k|n<k=1+min(k-n)n|j<-k+4=(n-k)%j
(%2)

Provalo online!

Zero indicizzati. Un metodo ricorsivo.



5

Buccia , 8 byte

!…ṁoe1DN

1-indicizzati. Provalo online!

Spiegazione

!…ṁoe1DN  Implicit input (an integer).
       N  Positive integers: [1,2,3,4,...
  ṁo      Map and concatenate
      D   double: [2,4,6,8,...
    e1    then pair with 1: [1,2,1,4,1,6,1,8,...
 …        Fill gaps with ranges: [1,2,1,2,3,4,3,2,1,2,3,4,5,6,...
!         Index with input.

3

Perl 6 , 29 byte

{({|(1...$+=2...2)}...*)[$_]}

Provalo online

0-based

Allargato:

{  # bare block lambda with implicit parameter 「$_」

  (
    # generate an outer sequence

    {           # bare block lambda

      |(        # flatten into outer sequence

        # generate an inner sequence

        1       # start at 1

        ...     # go (upward) towards:

        $       # an anonymous state variable (new one for each outer sequence)
          += 2  # increment by 2

        ...     # go (downward) towards:

        2       # stop at 2 (1 will come from the next inner sequence)

      )
    }

    ...         # keep generating the outer sequence until:
    *           # never stop

  )[ $_ ]       # index into outer sequence
}

La sequenza interna 1...$+=2...2produce

(1, 2).Seq
(1, 2, 3, 4, 3, 2).Seq
(1, 2, 3, 4, 5, 6, 5, 4, 3, 2).Seq
(1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2).Seq
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2).Seq
...

Per renderlo basato su 1, aggiungi 0,prima del secondo {o aggiungi -1dopo$_


3

R, 64 byte

function(n)unlist(sapply(seq(2,n,2),function(x)c(2:x-1,x:2)))[n]

Funzione che accetta un argomento n. Crea un vettore 2:ncon incrementi di 2. Per ognuno di questi, il vettore 1:(x-1)e x:2viene creato. Questo in totale sarà più lungo di n. Lo facciamo unlist, per ottenere un vettore e prendere la nnona voce.


Potresti fare 1:n*2invece di seq(2,n,2)? Sarà più grande del necessario, ma dovrebbe andare bene! Anche io non credo che questo ha lavorato con seq(2,n,2)per n=1comunque!
Giuseppe,

2

Python 2 , 56 byte

def f(x):n=int((x/2)**.5);print 2*n-abs(2*n*n+2*n+1-x)+2

Provalo online!

Questo è 0-indicizzato.

-1 byte grazie a @JustinMariner

Come funziona

Notiamo che il gruppo 1-indicizzato n( 1, 2, ... 2n ..., 2, 1) si verifica da elementi numerati da 0-indicizzati 2(n-1)^2a 2n^2.

Per trovare l'elemento all'indice x, possiamo trovare il numero del gruppo in ncui si xtrova. Da quel, calcoliamo la distanza dal centro del gruppo che xè. (Questa distanza è abs(2*n**2+2*n+2-x)).

Tuttavia, poiché gli elementi diminuiscono ulteriormente dal centro di un gruppo, sottraggiamo la distanza dal valore massimo del gruppo.


Ho giocato a golf questa parte: print 2*n-abs(2*n*n+2*n+1-x)+2- 2*n*n+2*npuò essere 2*n*-~ne +2+2*npuò essere trasformato -~n*2, il che ci consente di spostarlo all'inizio che salva byte ( 53 byte )
Mr. Xcoder


2

JavaScript, 39 byte

f=(n,t=2)=>n>t?f(n-t,t+4):n>t/2?t-n+2:n

2

Gelatina , 10 , 9 byte

ḤŒḄṖµ€Fị@

Provalo online!

Anche 1 indicizzato e termina abbastanza velocemente.

Un byte salvato grazie a @ErikTheOutgolfer!

Spiegazione:

Ipoteticamente, supponiamo che input ( a) sia 3.

    µ€      # (Implicit) On each number in range(a):
            #
Ḥ           # Double
            #   [2, 4, 6]
            #
 ŒḄ         # Convert to a range, and Bounce
            #   [[1, 2, 1], [1, 2, 3, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]]
            #
   Ṗ        # Pop
            #   [[1, 2], [1, 2, 3, 4, 3, 2], [1, 2, 3, 4, 5, 6, 5, 4, 3, 2]]
            #
     F      # Flatten
            #   [1, 2, 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2]
            #
      ị@    # Grab the item[a]
            #   1
            #

Il tuo codice è equivalente a Ḥ€ŒḄ€Ṗ€Fị@, quindi puoi usarlo µ€per -1 (tre o più monadi con all'inizio):ḤŒḄṖµ€Fị@
Erik the Outgolfer

Questo dovrebbe davvero essere ḤŒḄṖ<newline> ½ĊÇ€Fị@affinché 12 sia conforme al requisito di 10.000 (l'esecuzione del codice a 9 byte in locale richiede circa 2:20 sul mio i7 e utilizza 7 GB)
Jonathan Allan

1

MATL , 15 byte

li:"@EZv4L)]vG)

1-based.

Provalo online!

Questo è scaduto per i più grandi casi di test in TIO, ma termina in tempo sul mio computer desktop (compilatore in esecuzione su MATLAB R2017a). Per visualizzare il tempo trascorso, aggiungere Z`alla fine del codice.

>> matl 'li:"@EZv4L)]vG)Z`'
> 10000
84
15.8235379852476

Spiegazione

Il codice genera molti più termini del necessario. In particolare, calcola i n"pezzi" della sequenza, in cui ogni pezzo è un conto alla rovescia e torna a 1.

l       % Push 1
i       % Push input, n
:       % Range [1 2 ...n]
"       % For each k in that range
  @E    %   Push 2*k
  Zv    %   Symmetric range: [1 2 ... 2*k-1 2*k 2*k-1 ... 2 1]
  4L)   %   Remove last entry: [1 2 ... 2*k-1 2*k 2*k-1 ... 2]
]       % End
v       % Concatenate all stack contents into a column vector
G)      % Get n-th entry. Implicitly display

simpatico! TIO a volte è lento ...

1
Bene, la causa principale della lentezza qui è l'algoritmo (che genera molti più termini del necessario). Inoltre, il compilatore MATL non è particolarmente veloce
Luis Mendo il

1

Buccia , 12 10 byte

!ṁ§¤+hḣṫİ0

Provalo online!

1-indicizzato, funziona abbastanza velocemente

Spiegazione

!ṁ§¤+hḣṫİ0
 ṁ      İ0    Map the following function over the even numbers and concatenate the results together
  §   ḣṫ      Get the ranges 1-n and n-1, then... 
   ¤+h         remove the last element from both of them and concatenate them together
!             Return the element of the resulting list at the given index

8 byte utilizzando
Zgarb

@Zgarb è un'ottima idea e probabilmente dovresti pubblicarla come risposta :)
Leo



1

Retina , 62 byte

.+
$*
^((^.|\2..)*)\1.
6$*1$2$2;1
(?=.+;(.+))\1(.+).*;\2.*
$.2

Provalo online! Il link include casi di test. L'input è 1 indicizzato. Il primo stadio è solo la conversione da decimale a unaria. Il secondo stadio trova il numero quadrato più alto sstrettamente inferiore alla metà di n; $1è , mentre $2è 2s-1. Calcola due valori, prima il numero di numeri nella corsa corrente su / giù, che è 4(s+1) = 4s+4 = 2$2+6, e in secondo luogo la posizione all'interno di quella corsa, che è n-2s² = n-(2$1+1)+1 = n-$&+1, che richiede solo un 1compenso per l' 1usato per far rispettare la rigida disuguaglianza. La fase finale conta quindi da quella posizione sia all'inizio che alla fine della corsa e prende il risultato più basso e lo converte in decimale.



1

Perl 5 , 43 + 1 (-p) = 44 byte

$_=($n=2*int sqrt$_/2)+2-abs$n/2*$n+$n+1-$_

Provalo online!

Stavo lavorando su una formula per calcolare direttamente l'n-esimo elemento. Poi ho visto che @ fireflame241 aveva fatto quel lavoro e l'ho inserito nel Perl.

# Perl 5 , 50 + 1 (-n) = 51 byte

push@r,1..++$",reverse 2..++$"while@r<$_;say$r[$_]

Provalo online!

I risultati sono 0 indicizzati.


1

Haskell , 115 81 byte

y%x=snd(span(<x)$scanl(+)y[y+1,y+3..])!!0
g 1=1
g x|1%x>2%x=1+g(x-1)|1>0=g(x-1)-1

Provalo online!

C'è della magia in corso qui. Probabilmente potrebbe essere più breve se ho usato un approccio normale.

Spiegazione

Per prima cosa definiamo %. %è una funzione che accetta due variabili xe y. Costruisce un elenco scanl(+)y[y+1,y+3..]e trova il primo elemento di tale elenco maggiore di x. scanl(+)esegue solo somme iterative, per ottenere i numeri triangolari che faremmo scanl(+)0[1..], per ottenere i numeri quadrati che faremmo scanl(+)0[1,3..]. Le due liste in particolare che costruiremo sono scanl(+)2[3,5..]e scanl(+)1[2,4..]questi sono i punti di flesso del modello.

Ora definiamo la funzione principale gche accetta un x. Se xè uno, torniamo 1perché è il primo valore. Altrimenti controlliamo i prossimi due punti di flesso, se la flessione verso il basso è maggiore 1%x>2xrestituiamo il successore di g$x-1altrimenti restituiamo il predecessore di g$x-1.

Ok ma perché funziona?

Prima di tutto "Qual è il modo in cui troviamo i vertici?". È importante notare la distanza tra vertici consecutivi dello stesso tipo. Noterai che le differenze aumentano di 2 ogni volta. Questo ha senso perché le basi dei triangoli si allargano di 2 ogni volta. Possiamo fare una differenza costante di un elenco usando un elenco letterale simile [2,4..]e usiamo scanl(+)per trasformare questi elenchi nei nostri elenchi di vertici, in base alla posizione del primo vertice e della prima differenza.

Quindi ora che abbiamo un modo per trovare vertici verso l'alto e verso il basso, possiamo usare queste informazioni per ottenere i valori. Diciamo che il primo valore è 1altrimenti dobbiamo prendere il successore o il predecessore. Se il prossimo vertice è ascendente, vogliamo prendere il predecessore, altrimenti prendiamo il successore.

Haskell , 56 51 46 byte

Ecco la mia soluzione migliore con meno matematica e meno byte.

d x|e<-[1..x-1]=e++map(x+1-)e
(([1..]>>=d)!!0)

Provalo online!


1

Pyke , 14 byte

SF}SDtO_+)sQt@

Provalo qui!

S              -    range(1, input)
 F}SDtO_+)     -   for i in ^:
  }            -      ^ * 2
   S           -     range(1, ^)
        +      -    ^ + v
     tO_       -     ^[1:-1:-1]
          s    -  sum(^)
           Qt@ - ^[input-1]

1

C # (.NET Core) , 120 byte

Spiegazione: abbastanza semplice, il primo ciclo nidificato sale al massimo, il secondo torna indietro a 2. La ripetizione per ogni multiplo di 2.

x=>{var a=0;for(int i=2,j=0;j<x;i+=2){for(var b=1;b<=i&j<x;b++,j++){a=b;}for(var c=i-1;c>1&j<x;c--,j++){a=c;}}return a;}

Provalo online!


1

Rubino , 78 75 byte

Salvato 1 byte grazie a Step Hen

Salvato 1 byte grazie a Mr. Xcoder

->n{a=0;b=2;c=1;n.times{if a==b then c=0;b+=2;end;c=1if a<2;a+=c<1?-1:1};a}

Provalo online!

Spero di ottenere qualche consiglio per ridurre di più il numero di dipendenti. Ho provato ad adottare un approccio semplice.


Benvenuti in PPCG! c=1 ifpuò essere giocato a golf ac=1if
Stephen il

76 byte:->n{a=0;b=2;c=1;n.times{if a==b then c=0;b+=2;end;c=1if a==1;a+=c<1?-1:1};a}
Mr. Xcoder il

1

Java (OpenJDK 8) , 53 byte

n->{int i=2;for(;n>i;i+=4)n-=i;return n>i/2?i-n+2:n;}

Provalo online!

-2 byte grazie a Nevay.

1-indicizzati.

TL; DR Abbiamo diviso la sequenza in comodi blocchi, abbiamo trovato il pezzo ndentro, quindi abbiamo trovato la nthposizione nel pezzo.

Qui, possiamo dividere la sequenza come [[1,2],[1,2,3,4,3,2],[1,2,3,4,5,6,5,4,3,2],...], che ci dà dimensioni del pezzo di 4i-2. A partire da i=2, sottraiamo ida n, essenzialmente lo spostamento verso l'alto un pezzo alla volta. Una volta soddisfatti n<=i, sappiamo che nora è la posizione del valore corretto nel blocco corrente.

Otteniamo quindi il valore confrontando ncon ila dimensione del blocco. Il punto medio di ogni blocco è uguale a i/2+1; se nè inferiore a questo, ritorniamo semplicemente n. Se nè maggiore, torniamo i-n+2.

Esempio

n = 16, i = 2

Is n > i? Yes, n = n - 2 = 14, i = i + 4 = 6
Is n > i? Yes, n = n - 6 = 8, i = i + 4 = 10
Is n > i? No, stop looping.
10 / 2 + 1 = 6
Is n > 6? Yes, return i - n + 2 = 8 - 6 + 2 = 4

Non è necessario +1, return n>i/2?i-n+2:nè sufficiente.
Nevay,

Huh. Grazie, divisione intera.
Xanderhall,

1

Python 2 , 5! byte (120 byte: P)

r=range
a=[]
for i in r(2,998,2): 
	for j in r(1,i+1): a.append(j)
	for j in r(i-1,1,-1): a.append(j)
print a[input()-1]

Provalo online!

Semplice, crea l'elenco e quindi accetta l'input'th element


Grazie a chiunque abbia votato! Ora ho 50 rappresentanti in modo da poter commentare!
tampona

0

Python 3 , 184 156 byte

l,n,r=list,next,range
h=lambda x:l(r(1,x))+l(r(x-2,1,-1))
def g():
	x=3
	while True:yield from h(x);x+=2
def f(i):
	x=g()
	for _ in r(i-1):n(x)
	return n(x)

Provalo online!

giocato a golf con generatore Python per una valutazione "pigra"


0

QBIC , 47 byte

g=q{p=p+1~p=:|_Xg\g=g+q~g=1or g>=r|r=r+1┘q=q*-1

Spiegazione

g=q         var g is the current value of the sequence; set to 1 at the start
{           DO infinitely
p=p+1       raise the step counter (var p)
~p=:|_Xg    IF p equals the input term a (read from cmd line) THEN QUIT, printing g
\           ELSE
g=g+q       raise (or decrement) g by q (q is 1 at the start of QBIC)
~g=1        IF g is at the lower bound of a subsequence
    or g>=r OR g is at the upper bound (r start as 2 in QBIC)
|r=r+1      THEN increment r (this happens once on lower bound, and once on upper, 
            total of 2 raise per subsequence)
┘q=q*-1     and switch q from 1 to -1

0

Röda , 54 byte

f n{seq 1,n|{|i|seq 1,2*i;seq 2*i-1,2}_|head n+2|tail}

Provalo online!

Chiama con: try f(n)

Questa funzione restituisce rapidamente la risposta, ma successivamente esegue alcuni calcoli non necessari e alla fine la memoria si esaurisce.

Poiché la funzione restituisce la risposta effettiva poco dopo la sua chiamata (chiaramente meno di un minuto), penso che questa risposta sia valida.

(In Röda le funzioni possono restituire valori prima di uscire a causa del parallelismo.)


0

C # (.NET Core) , 99 95 86 byte

n=>{int i=1,t=2,d=0;for(;n>1;){i+=1-2*d;if(i==t){d++;t+=2;}if(i==1)d--;n--;}return i;}

Provalo online!

Funzione lambda che accetta e restituisce un numero intero. Ciclo singolo che gestisce il conteggio su e giù.


0

PHP, 65 + 1 byte

for($x=$d=$z=1;--$argn;)$d=($x+=$d)>1?$x>$z?-1:$d:!!$z+=2;echo$x;

Esegui come pipe con -Ro provalo online (o decommenta una delle altre versioni).

Una porta del JavaScript ricorsivo di tsh richiede 66 byte:

function f($n,$t=2){return$t<2*$n?$t<$n?f($n-$t,$t+4):$t-$n+2:$n;}

Una soluzione port di Arnauld richiede 62 + 1:

$n=$argn;echo($n-=($r=(~-$n/2)**.5|0)*$r*2)<++$r*2?$n:$r*4-$n;

Un porto golfizzato di Java di Xanderhall ha finora il codice più breve (55 + 1 byte):

for($n=$argn;$n+2>$i+=4;)$n-=$i-2;echo$n*2>$i?$i-$n:$n;

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.