Flip del triangolo numerico


30

Supponi di elencare gli interi positivi in ​​un triangolo, quindi capovolgili da sinistra a destra. Dato un numero, genera il numero a cui è inviato. Questa è una mappatura auto-inversa.

         1                      1         
       2   3                  3   2       
     4   5   6    <--->     6   5   4     
   7   8   9  10         10   9   8   7   
11  12  13  14  15     15  14  13  12  11

Questo è l'ennesimo elemento di A038722 , con un indice:

1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...

Questa sequenza inverte blocchi contigui degli interi positivi con lunghezze crescenti:

 1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...
<-><----><-------><-----------><------------------>

Casi test:

1 -> 1
2 -> 3
3 -> 2
4 -> 6
14 -> 12
990 -> 947
991 -> 1035
1000 -> 1026
1035 -> 991
1036 -> 1081
12345 -> 12305

Classifica:

Risposte:


15

JavaScript (ES7), 26 byte

n=>((2*n)**.5+.5|0)**2-n+1

Un'implementazione della seguente formula di OEIS :

formula

dimostrazione


Mi piace l'operazione OR per tagliarla in un numero intero! bel lavoro!
CraigR8806,

7

Gelatina , 8 7 byte

RṁR€UFi

Grazie a @ErikTheOutgolfer per aver salvato 1 byte!

Provalo online!

Come funziona

RṁR€UFi  Main link. Argument: n

R        Range; yield [1, ..., n].
  R€     Range each; yield [[1], [1, 2], [1, 2, 3], ..., [1, ..., n]].
 ṁ       Mold the left argument like the right one, yielding
         [[1], [2, 3], [4, 5, 6], ...]. The elements of the left argument are 
         repeated cyclically to fill all n(n+1)/2 positions in the right argument.
    U    Upend; reverse each flat array, yielding [[1], [3, 2], [6, 5, 4], ...].
     F   Flatten, yielding [1, 3, 2, 6, 5, 4, ...].
      i  Index; find the first index of n in the result.

6

Alice , 27 byte

Grazie a Sp3000 per l' .Cidea.

/o
\i@/.2:e2,tE*Y~Z.H2*~.C+

Provalo online!

Spiegazione

Penso che potrebbe esserci un modo più breve per calcolare questo usando numeri triangolari, ma ho pensato che questo fosse un abuso interessante di un built-in, quindi ecco una soluzione diversa.

L'idea di base è quella di utilizzare i componenti "pack" e "unpack" di Alice. "Pack", oppure Z, prende due numeri interi e li mappa biiettivamente su un singolo numero intero. "Unpack", o Y, inverte questa biiezione e trasforma un numero intero in due. Normalmente, questo può essere usato per memorizzare un elenco o un albero di numeri interi in un singolo (grande) intero e recuperare i singoli valori in un secondo momento. Tuttavia, in questo caso possiamo usare le funzioni nell'ordine opposto, per consentire alla natura della biiezione di funzionare per noi.

La decompressione di un numero intero in due numeri interi consiste sostanzialmente di tre passaggi:

  1. Mappa ℤ → ℕ (incluso zero) con una semplice "piegatura". Cioè, mappare numeri interi negativi a naturali dispari e numeri interi non negativi a naturali pari.
  2. Mappa ℕ → ℕ 2 , utilizzando la funzione di associazione Cantor . Cioè, i naturali sono scritti lungo le diagonali di una griglia infinita e restituiamo gli indici:

       ...
    3  9 ...
    2  5 8 ...
    1  2 4 7 ...
    0  0 1 3 6 ...
    
       0 1 2 3
    

    Ad esempio 8sarebbe mappato alla coppia (1, 2).

  3. Mappa 2 → ℤ 2 , usando l'inverso del passaggio 1 su ciascun numero intero individualmente. Cioè, i naturali dispari vengono mappati su numeri interi negativi e persino i naturali vengono mappati su numeri interi non negativi.

Per impacchettare due numeri interi in uno, è sufficiente invertire ciascuno di questi passaggi.

Ora, possiamo vedere che la struttura della funzione di accoppiamento Cantor codifica convenientemente il triangolo di cui abbiamo bisogno (anche se i valori sono off-by-one). Per invertire queste diagonali, tutto quello che dobbiamo fare è sostituire la x ed y coordinate nella griglia.

Sfortunatamente, poiché tutti e tre i passaggi precedenti sono combinati in un unico built-in Y(o Z), dobbiamo annullare noi stessi le mappature ℤ → ℕ o ℕ → ℤ . Tuttavia, mentre lo facciamo, possiamo salvare un paio di byte usando direttamente i mapping ℕ + → ℤ o ℤ → ℕ + , per occuparci dell'errore off-by-one nella tabella. Quindi ecco l'intero algoritmo:

  1. Mappa + → ℤ utilizzando (n / 2) * (-1) n-1 . Questa mappatura è scelta in modo tale da annullare l'implicito ℤ → ℕ durante il disimballaggio, tranne per il fatto che il valore viene ridotto di 1.
  2. Decomprimi il risultato in due numeri interi.
  3. Scambiali.
  4. Comprimi nuovamente i valori scambiati in un unico numero intero.
  5. Mappa ℤ → ℕ + utilizzando | 2n | + (n≥0) . Ancora una volta, questa mappatura viene scelta in modo tale da annullare la mappatura implicita ℕ → ℤ durante l'imballaggio, tranne per il fatto che il valore aumenta di 1.

Detto questo, possiamo guardare al programma:

/o
\i@/...

Questo è semplicemente un framework per programmi aritmetici lineari con input e output interi.

.    Duplicate the input.
2:   Halve it.
e    Push -1.
2,   Pull up the other copy of the input.
t    Decrement.
E    Raise -1 to this power.
*    Multiply. We've now computed (n/2) * (-1)^(n-1).
Y    Unpack.
~    Swap.
Z    Pack.
.H   Duplicate the result and take its absolute value.
2*   Double.
~    Swap with other copy.
.C   Compute k-choose-k. That's 1 for k ≥ 0 and 0 for k < 0.
+    Add. We've now computed |2n| + (n≥0).



4

Ottava , 71 68 byte

3 byte salvati grazie a Conor O'Brien .

x=triu(ones(n=input('')));x(~~x)=1:nnz(x);disp(nonzeros(flip(x))(n))

Questo non funziona per input di grandi dimensioni a causa di limiti di memoria.

Provalo online!

Spiegazione

Considera l'input n = 4. Il codice crea prima la matrice

 1     1     1     1
 0     1     1     1
 0     0     1     1
 0     0     0     1

Poi sostituisce elementi non nulli per column-major (verso il basso, poi attraverso) da 1, 2, 3...:

 1     2     4     7
 0     3     5     8
 0     0     6     9
 0     0     0    10

Quindi capovolge la matrice verticalmente:

 0     0     0    10
 0     0     6     9
 0     3     5     8
 1     2     4     7

Infine, prende il nvalore non zero in ordine di colonna maggiore, che in questo caso è 6.


1
@ rahnema1 Questo eè geniale! Dovresti sicuramente pubblicarlo come risposta, insieme ad altri tuoi ottimi suggerimenti. Per quanto riguarda ans =, non sono mai sicuro che sia valido o meno
Luis Mendo,

4

Haskell , 31 byte

r=round
f n=r(sqrt$2*n)^2-r n+1

Provalo online!

Questa risposta usa solo la formula. È la risposta meno interessante qui, ma sembra anche la più golfistica.

Haskell , 38 36 34 byte

x!y|x<=y=1-x|v<-y+1=v+(x-y)!v
(!0)

Provalo online!

(!0) è la funzione senza punti di cui ci occupiamo.

Spiegazione

Vorrei iniziare dicendo che sono molto contento di questa risposta.

L'idea di base qui è che se rimuoviamo il numero triangolare più grande più piccolo del nostro input, possiamo invertirlo e aggiungere nuovamente il numero triangolare. Quindi definiamo un operatore !, !accetta i nostri input regolari x, ma richiede anche un numero aggiuntivo y. ytiene traccia delle dimensioni del numero triangolare crescente. Se x>yvogliamo ricorrere, diminuiamo xdi ye aumentiamo ydi uno. Quindi calcoliamo (x-y)!(y+1)e aggiungiamo y+1ad esso. Se x<=yabbiamo raggiunto il nostro caso di base, per invertire xla posizione nella riga del triangolo torniamo 1-x.

Haskell , 54 byte

f x|u<-div(x^2-x)2=[u+x,u+x-1..u+1]
(!!)$0:(>>=)[1..]f

Provalo online!

(!!)$0:(>>=)[1..]f è una funzione senza punti

Spiegazione

La prima cosa di cui ci occupiamo è f, fè una funzione che prende xe restituisce la xriga del triangolo in ordine inverso. Lo fa calcolando prima il x-1numero triangolare e assegnandolo a u. u<-div(x^2-x)2. Quindi restituiamo l'elenco [u+x,u+x-1..u+1]. u+xè il xth numero triangolare e il primo numero sulla riga, u+x-1è uno in meno di quello e il secondo numero sulla riga u+1è uno in più dell'ultimo numero triangolare e quindi l'ultimo numero sulla riga.

Una volta che fabbiamo formato un elenco (>>=)[1..]f, che è un appiattimento del triangolo. Aggiungiamo zero in primo piano in 0:modo che le nostre risposte non vengano compensate da una e forniamo alla nostra funzione di indicizzazione (!!).

Haskell , 56 byte

f 0=[0]
f x|u<-f(x-1)!!0=[u+x,u+x-1..u+1]
(!!)$[0..]>>=f

Provalo online!

Questo è di 2 byte più lungo ma un po 'più elegante secondo me.


3

C (gcc) , 48 byte

k,j,l;f(n){for(k=j=0;k<n;)l=k,k+=++j;n=1+k-n+l;}

Provalo online!

Probabilmente non ottimale, ma sono abbastanza contento di questo. Usa il fatto che

NTF N = T N + A057944 ( N ) - N + 1

(Se ho scritto la formula correttamente, cioè.)


Non stai chiamando return, ma viene utilizzato il valore a return. Questo è un comportamento indefinito.
2501

@ 2501 Finché il programma funziona, è consentito. E, scrivere nel primo argomento di una funzione equivale a restituire un valore.
Conor O'Brien,

E, scrivere nel primo argomento di una funzione equivale a restituire un valore. Non esiste nulla del genere nel linguaggio C. Lo standard dice anche esplicitamente che l'utilizzo del valore restituito da una funzione che non restituisce è un comportamento indefinito.
2501

1
@ 2501 Sembra che tu stia confondendo l'ambiente C (gcc) per la specifica C. Sì, il linguaggio C / la specifica lo definisce indefinito, ma è implementato come tale. Quindi quando dico "equivalente", mi riferisco sicuramente all'implementazione di C da parte di gcc e della maggior parte degli altri compilatori. Su PPCG, non scriviamo codice "perfetto" - molto codice va contro le specifiche per il gusto del golf. Come ho detto, finché funziona, è una risposta valida.
Conor O'Brien

@ 2501 Ti incoraggio a leggere alcuni articoli sul meta sito, in particolare questo .
Conor O'Brien,

2

05AB1E , 30 byte

U1V[YLO>X›iYLOX-UY<LO>X+,q}Y>V

Provalo online!


Stavo per dire "Cosa? Una risposta 05AB1E senza Unicode?" ma poi l'unico personaggio non ASCII lo rovina ...: P Bella prima risposta, però, benvenuta in Puzzle di programmazione e Code Golf!
clismique,

@ Qwerp-Derp Grazie mille! Ho appena iniziato a imparare questa lingua, quindi non mi sorprende che la mia risposta sia stata così negativa.
Eduardo Hoefel,

2

Buccia , 6 byte

!ṁ↔´CN

Provalo online!

Spiegazione

!ṁ↔´CN  -- implicit input N, for example: 4
   ´ N  -- duplicate the natural numbers:
           [1,2,3,…] [1,2,3,…]
    C   -- cut the second argument into sizes of the first:
           [[1],[2,3],[4,5,6],[7,8,9,10],…]
 ṁ↔     -- map reverse and flatten:
           [1,3,2,6,5,4,10,9,8,7,15,…
!       -- index into that list:
           6

2

tinylisp , 78 byte

(d _(q((R N T)(i(l T N)(_(a R 1)N(a T R))(a 2(a T(s T(a N R
(d f(q((N)(_ 2 N 1

Definisce una funzione fche esegue la mappatura. Provalo online!

Ungolfed

Troviamo il numero triangolare più piccolo che è maggiore o uguale al numero di input, nonché in quale riga del triangolo si trova il nostro numero. Da questi, possiamo calcolare la versione capovolta del numero.

  • Se il numero triangolare corrente è inferiore a N, ricorrere alla riga successiva del triangolo. (Trattiamo la riga superiore come riga 2 per semplificare la matematica.)
  • Altrimenti, la versione capovolta di N è (TN) + (TR) +2.

La funzione principale flipchiama semplicemente la funzione di supporto a _flippartire dalla riga superiore.

(load library)

(def _flip
 (lambda (Num Row Triangular)
  (if (less? Triangular Num)
   (_flip Num (inc Row) (+ Triangular Row))
   (+ 2
    (- Triangular Num)
    (- Triangular Row))))))

(def flip
 (lambda (Num) (_flip Num 2 1)))

1

05AB1E , 9 byte

·LD£í˜¹<è

Provalo online!

Spiegazione

·L          # push range [1 ... 2n]
  D         # duplicate
   £        # split the first list into pieces with size dependent on the second list
    í       # reverse each sublist
     ˜      # flatten
      ¹<è   # get the element at index <input>-1

Sfortunatamente, l'appiattimento di array non gestisce molto bene elenchi più grandi.
Al costo di 1 byte potremmo fare · t2z + ïn¹-> usando la formula matematica floor(sqrt(2*n)+1/2)^2 - n + 1trovata su OEIS .


1

Lotto, 70 byte

@set/ai=%2+1,j=%3+i
@if %j% lss %1 %0 %1 %i% %j%
@cmd/cset/ai*i+1-%1

Utilizza un ciclo per trovare l'indice del numero triangolare almeno grande quanto n.




0

APL (Dyalog), 27 byte

Ho due soluzioni allo stesso tempo.

Un treno:

⊢⊃⊃∘(,/{⌽(+/⍳⍵-1)+⍳⍵}¨∘⍳)

Provalo online!

E un dfn:

{⍵⊃⊃((⍳⍵),.{1+⍵-⍳⍺}+\⍳⍵)}

Provalo online!

Entrambe queste soluzioni creano prima il triangolo capovolto e quindi estraggono l'elemento nell'indice indicato dall'argomento ( 1basato su).


0

J, 25 byte

3 :'>:y-~*:>.-:<:%:>:8*y'

Come spiegazione, considera f(n) = n(n+1)/2. f(r), data la riga r, restituisce il numero più a sinistra della rth riga del triangolo speculare. Adesso, considera g(n) = ceiling[f⁻¹(n)]. g(i), dato l'indicei , restituisce la riga su cui si trova l'indice i. Quindi, f(g(n))restituisce il numero più a sinistra della riga su cui si trova l'indice n. Quindi, h(n) = f(g(n)) - (n - f(g(n)-1)) + 1è la risposta al problema sopra.

Semplificando, otteniamo h(n) = [g(n)]² - n + 1 = ceiling[(-1 + sqrt(1 + 8n))/2]² - n + 1.

Dagli sguardi della formula di @ Arnauld, sembra che:

ceiling[(-1 + sqrt(1 + 8n))/2] = floor[1/2 + sqrt(2n)].


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.