Contar para frente e depois dobrar


24

Vamos contar...

Conte até 2 e volte para 1
Conte até 4 e volte para 1
Conte até 6 e volte para 1
... ok, você conseguiu ...

junte tudo isso e você terá a seguinte sequência

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

Desafio
Dado um número inteiro n>0para indexado em 1 (ou n>=0para indexado em 0), imprima o enésimo termo dessa sequência

Casos de teste

Input->Output  

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

Regras

seu programa deve ser capaz de calcular soluções de até n = 10000 em menos de um minuto

Isso é , então o código mais curto em bytes vence!


2
Quem decide o que leva um minuto? Uma máquina de Turing ideal para o tempo construída a partir de lego levaria muito tempo, enquanto a mesma máquina de Turing simulada em, digamos, C, presumivelmente levaria segundos ou minutos, dependendo do processador em que é executado. Portanto, se eu enviar a descrição da máquina de Turing, ela é válida?
Arthur

2
@Arthur Eu acho que você pode entender por que eu fiz essa restrição ... Eu não queria que um algoritmo levasse "para sempre" para encontrar n = 10000 produzindo uma lista enorme. A maioria das pessoas aqui deu respostas brilhantes que encontram milhões em segundos.

4
@ BillSteihn Acho que a restrição é desnecessária.
Erik the Outgolfer

2
@EriktheOutgolfer respostas do gode golf podem ser complicadas ... sem a restrição, uma resposta que produz 10.000 tuplas [1,2 ... 2n..2,1] seria válida. A restrição é apenas para respostas como essa. Não vejo onde está o problema. Só quero que sua resposta encontre todos os casos de teste em um período de tempo razoável.

3
@StraklSeth O consenso geral aqui é que ele deve funcionar na teoria, não necessariamente na prática.
Erik the Outgolfer

Respostas:


16

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

Guardado 1 byte graças a Titus

Entrada esperada: 1 indexada.

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

Inicialmente inspirado por uma fórmula para A004738 , que é uma sequência semelhante. Mas acabei reescrevendo por completo.

Casos de teste

Quão?

A sequência pode ser organizada como um triângulo, com a parte esquerda em ordem crescente e a parte direita em ordem decrescente.

Abaixo estão as primeiras 4 linhas, contendo os 32 primeiros termos:

            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

Agora, vamos apresentar algumas variáveis:

 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

Começamos com 2 elementos na parte superior e adicionamos 4 elementos em cada nova linha. Portanto, o número de elementos na linha indexada 0 r pode ser expresso como:

a(r) = 4r + 2

A posição inicial indexada 1 x da linha r é dada pela soma de todos os termos anteriores nesta série aritmética mais um, o que leva a:

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

Reciprocamente, dada uma posição indexada em 1 n na sequência, a linha correspondente pode ser encontrada com:

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

ou como código JS:

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

Uma vez que conhecemos r (n) , subtraímos a posição inicial x (r) menos uma de n :

n -= r * r * 2

Comparamos n com a (r) / 2 + 1 = 2r + 2 para descobrir se estamos na parte ascendente ou na parte descendente:

n < ++r * 2 ?

Se essa expressão for verdadeira, retornamos n . Caso contrário, retornamos 4 (r + 1) - n . Mas como r já foi incrementado na última instrução, isso é simplificado como:

n : r * 4 - n

11
Ok, acho que entendi. O comprimento de cada parte de cima para baixo é 2,6,10,14 ... então a soma cresce com o quadrado da contagem de linhas, daí o sqrt. Muito agradável!
JollyJoker



5

Casca , 8 bytes

!…ṁoe1DN

1 indexado. Experimente online!

Explicação

!…ṁ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 bytes

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

Experimente online

Baseado em 0

Expandido:

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

A sequência interna 1...$+=2...2produz

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

Para que seja baseado em 1, adicione 0,antes do segundo {ou -1depois$_


3

R, 64 bytes

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

Função que aceita um argumento n. Ele cria um vetor 2:ncom incrementos de 2. Para cada um deles, o vetor 1:(x-1)e x:2é criado. Isso no total será maior que n. Nós unlist, para obter um vetor e pegar a n-ésima entrada.


Você poderia fazer em 1:n*2vez de seq(2,n,2)? Será maior do que você precisa, mas tudo bem! Também não acho que isso funcionou seq(2,n,2)de n=1qualquer maneira!
Giuseppe

2

Python 2 , 56 bytes

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

Experimente online!

Este é o índice 0.

-1 byte graças a @JustinMariner

Como isso funciona

Observamos que o 1 º ngrupo indexado ( 1, 2, ... 2n ..., 2, 1) ocorre de elementos numerados como 0 indexados 2(n-1)^2a 2n^2.

Para encontrar o elemento no índice x, podemos encontrar o número do grupo nque xestá dentro. A partir disso, calculamos a distância do centro do grupo que xestá. (Esta distância é abs(2*n**2+2*n+2-x)).

No entanto, como os elementos diminuem mais para longe do centro de um grupo, subtraímos a distância do valor máximo do grupo.


Eu tenho golfed esta parte: print 2*n-abs(2*n*n+2*n+1-x)+2- 2*n*n+2*npode ser 2*n*-~ne +2+2*npode ser transformado em -~n*2, o que nos permite movê-lo para o início o que economiza bytes ( 53 bytes )
Mr. Xcoder

2

05AB1E , 8 bytes

Código:

ÅÈ€1Ÿ¦¹è

Usa a codificação 05AB1E . Experimente online!

Explicação:

ÅÈ           # Get all even numbers until input (0, 2, ..., input)
  €1         # Insert 1 after each element
    Ÿ        # Inclusive range (e.g. [1, 4, 1] -> [1, 2, 3, 4, 3, 2, 1])
     ¦       # Remove the first element
      ¹è     # Retrieve the element at the input index

5
Não funciona corretamente a menos que você remova | , que também guarda um ofc byte :)
Emigna

€1é estranho ...
Magic Octopus Urn

2

JavaScript, 39 bytes

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

2

Geléia , 10 , 9 bytes

ḤŒḄṖµ€Fị@

Experimente online!

Também indexado, e termina muito rápido.

Um byte economizado graças a @ErikTheOutgolfer!

Explicação:

Hipoteticamente, digamos que a entrada ( a) seja 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
            #

Seu código é equivalente a Ḥ€ŒḄ€Ṗ€Fị@, então você pode usar µ€para -1 (três ou mais mônadas com no início):ḤŒḄṖµ€Fị@
Erik the Outgolfer

Isso deve ser realmente ḤŒḄṖ<newline> ½ĊÇ€Fị@para 12 a cumprir o requisito 10.000 (executando o código 9 byte leva localmente cerca de 2:20 no meu i7 e usa 7GB)
Jonathan Allan

1

MATL , 15 bytes

li:"@EZv4L)]vG)

Baseado em 1.

Experimente online!

Isso expira nos maiores casos de teste do TIO, mas termina no meu computador desktop (compilador executado no MATLAB R2017a). Para exibir o tempo decorrido, adicione Z`no final do código.

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

Explicação

O código gera muitos mais termos do que o necessário. Especificamente, ele calcula n"peças" da sequência, onde cada peça é uma contagem até 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

legais! TIO é lento às vezes ...

11
Bem, a principal causa de lentidão aqui é o algoritmo (que gera muito mais termos do que o necessário). Além disso, o compilador MATL não é particularmente rápido
Luis Mendo

1

Casca , 12 10 bytes

!ṁ§¤+hḣṫİ0

Experimente online!

Indexado em 1, funciona muito rápido

Explicação

!ṁ§¤+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 bytes usando
Zgarb 23/08

@Zgarb que é uma grande idéia e você provavelmente deve publicá-la como sua resposta :)
Leo



1

Retina , 62 bytes

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

Experimente online! O link inclui casos de teste. A entrada é indexada em 1. O primeiro estágio é apenas a conversão decimal para unária. O segundo estágio encontra o número quadrado mais alto sestritamente menos da metade de n; $1é , enquanto $2é 2s-1. Ele calcula dois valores, primeiro o número de números na execução atual de subida / descida, que é 4(s+1) = 4s+4 = 2$2+6, e em segundo lugar a posição dentro dessa execução, ou seja n-2s² = n-(2$1+1)+1 = n-$&+1, que requer apenas um 1para compensar o 1usado para impor a desigualdade estrita. O estágio final conta a partir dessa posição até o início e o final da corrida, pega o resultado mais baixo e o converte em decimal.



1

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

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

Experimente online!

Eu estava trabalhando em uma fórmula para calcular o n-ésimo elemento diretamente. Então vi que o @ fireflame241 havia feito esse trabalho e joguei no Perl.

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

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

Experimente online!

Os resultados são 0 indexados.


1

Haskell , 115 81 bytes

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

Experimente online!

Há alguma mágica acontecendo aqui. Provavelmente poderia ser mais curto se eu usasse uma abordagem normal.

Explicação

Primeiro nós definimos %. %é uma função que aceita duas variáveis xe y. Ele constrói uma lista scanl(+)y[y+1,y+3..]e encontra o primeiro elemento dessa lista maior que x. scanl(+)apenas realiza somas iterativas, para obter os números triangulares que faríamos scanl(+)0[1..], para obter os números quadrados que faríamos scanl(+)0[1,3..]. As duas listas em particular que iremos construir são scanl(+)2[3,5..]escanl(+)1[2,4..] estes são os pontos de inflexão do padrão.

Agora vamos definir a função principal gque recebe um x. Se xfor um, retornamos 1porque esse é o primeiro valor. Caso contrário, verificamos os próximos dois pontos de inflexão; se a inflexão descendente for maior 1%x>2x, retornamos o sucessor de, g$x-1caso contrário, retornamos o predecessor deg$x-1 .

Ok, mas por que isso funciona?

Primeiro de tudo "O que há com a maneira como encontramos vértices?". É importante observar a distância entre vértices consecutivos do mesmo tipo. Você notará que as diferenças aumentam 2 por vez. Isso faz sentido porque as bases dos triângulos se tornam mais amplas em 2 a cada vez. Podemos fazer uma lista constante diferença usando uma lista literal assim [2,4..]e usamosscanl(+) transformar essas listas em nossas listas de vértices, com base na localização do primeiro vértice e da primeira diferença.

Portanto, agora que temos uma maneira de encontrar vértices para cima e para baixo, podemos usar essas informações para obter os valores. Dizemos que o primeiro valor é o 1contrário, temos que pegar o sucessor ou o predecessor. Se o próximo vértice for ascendente, queremos assumir o predecessor, caso contrário, o sucessor.

Haskell , 56 51 46 bytes

Aqui está minha melhor solução com menos matemática e menos bytes.

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

Experimente online!


1

Pyke , 14 bytes

SF}SDtO_+)sQt@

Experimente aqui!

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 bytes

Explicação: bastante simples, o primeiro loop aninhado sobe até o máximo, o segundo desce novamente para 2. A repetição para cada múltiplo de 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;}

Experimente online!


1

Ruby , 78 75 bytes

Guardado 1 byte graças a Step Hen

Economizou 1 byte graças ao Sr. 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}

Experimente online!

Espero conseguir algumas dicas para diminuir ainda mais o número de bytes. Eu tentei adotar uma abordagem simples.


Bem-vindo ao PPCG! c=1 ifpode ser jogado parac=1if
Stephen

76 bytes:->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}
Sr. Xcoder

1

Java (OpenJDK 8) , 53 bytes

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

Experimente online!

-2 bytes graças a Nevay.

1 indexado.

TL; DR Dividimos a sequência em pedaços convenientes, localizamos o pedaço ne encontramos a nthposição no pedaço.

Aqui, podemos dividir a sequência como [[1,2],[1,2,3,4,3,2],[1,2,3,4,5,6,5,4,3,2],...], o que nos fornece tamanhos de partes de 4i-2. Começando com i=2, subtraímos ide n, essencialmente movendo para cima um pedaço de cada vez. Quando satisfazemos n<=i, sabemos que nagora é a posição do valor correto no pedaço atual.

Em seguida, obtemos o valor comparando ncom io tamanho do bloco. O ponto médio de cada pedaço é igual a i/2+1; se nfor menor que isso, simplesmente retornamos n. Se nfor maior, retornamosi-n+2 .

Exemplo

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

Você não precisa do +1, return n>i/2?i-n+2:né suficiente.
Nevay

Hã. Obrigado, divisão inteira.
Xanderhall

1

Python 2 , 5! bytes (120 bytes: 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]

Experimente online!

Simples, faz a lista e depois pega o elemento input'th


Obrigado quem votou! Agora tenho 50 representantes para poder comentar! dabs intensamente
Husnain Raza 26/08

0

Python 3 , 184 156 bytes

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)

Experimente online!

jogou golfe com o gerador Python para avaliação "preguiçosa"


0

QBIC , 47 bytes

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

Explicação

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 bytes

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

Experimente online!

Ligue para: try f(n)

Essa função retorna rapidamente a resposta, mas depois disso faz alguns cálculos desnecessários e acaba ficando sem memória.

Como a função retorna a resposta real logo após ser chamada (claramente em menos de um minuto), acho que essa resposta é válida.

(No Röda, as funções podem retornar valores antes de sair devido ao paralelismo.)


0

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

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

Experimente online!

Função Lambda que pega e retorna um número inteiro. Loop único que lida com a contagem para cima e para baixo.


0

PHP, 65 + 1 bytes

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

Executar como tubo com -Rou tente online (ou remova o comentário de uma das outras versões).

Uma porta do JavaScript recursivo do tsh leva 66 bytes:

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

Um porto da solução da Arnauld leva 62 + 1:

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

Uma porta golfada do Java de Xanderhall tem o código mais curto até agora (55 + 1 bytes):

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.