Genera n dígitos de la secuencia de Gijswijt

19

Introducción

La secuencia de Gijswijt ( A090822 ) es realmente famosa, REALMENTE lenta. Para ilustrar:

  • Los primeros 3 aparecen en el noveno término (está bien).
  • Los primeros 4 aparecen en el término 220 (muy lejos, pero factible).
  • Los primeros 5 aparecen en (aproximadamente) el término 10 ^ (10 ^ 23) (solo no).
  • Nadie sabe realmente dónde están los primeros 6 ... se sospecha que está en el ...

    2 ^ (2 ^ (3 ^ (4 ^ 5))) th término.

Puede suponer que no tendrá que lidiar con un número de dos dígitos.

La secuencia se genera así:

  1. El primer término es 1.
  2. Cada término después de eso es la cantidad de "bloques" repetidos anteriores (si hay múltiples "bloques" repetidos, se usa la mayor cantidad de bloques repetidos).

Para aclarar, aquí están los primeros términos.

1 -> 1, 1(un bloque repetitivo ( 1), por lo que el dígito registrado es 1)

1, 1 -> 1, 1, 2(dos bloques repetidos ( 1), por lo que el dígito registrado es 2)

1, 1, 2 -> 1, 1, 2, 1(un bloque repetitivo ( 2o 1, 1, 2), por lo que el dígito registrado es 1)

1, 1, 2, 1 -> 1, 1, 2, 1, 1 (entiendes la idea)

1, 1, 2, 1, 1 -> 1, 1, 2, 1, 1, 2

1, 1, 2, 1, 1, 2 -> 1, 1, 2, 1, 1, 2, 2(dos bloques repetidos ( 1, 1, 2), por lo que el dígito registrado es 2)

Tarea

Su tarea es, como se indica en la pregunta, generar n dígitos de la secuencia de Gijswijt.

Instrucciones

  • La entrada será un número entero n.
  • Su código puede generar los dígitos en cualquier forma (una lista, múltiples salidas, etc.).

Este es el código de golf, por lo que gana el código más corto en bytes.

clismique
fuente

Respuestas:

7

Pyth, 25 22 21 bytes

t_u+eSmtfxG*Td1._GGQN

OP confirmó que solo necesitamos manejar números de un solo dígito. Esto permitió almacenar la lista como una cadena de dígitos. -> Guardado 3 bytes

Pruébelo en línea: demostración

Explicación:

t_u+...GQN      implicit: Q = input number
         N      start with the string G = '"'
  u     Q       do the following Q times:
    ...            generate the next number
   +   G           and prepend it to G
 _              print reversed string at the end
t               remove the first char (the '"')

Y así es como genero el siguiente número:

eSmtfxG*Td1._G
           ._G    generate all prefixes of G
  m               map each prefix d to:
    f     1          find the first number T >= 1, so that:
       *Td              d repeated T times
     xG                 occurs at the beginning of G
 S                  sort all numbers
e                   take the last one (maximum)   

21 bytes con listas

_u+eSmhhrcGd8SlGGtQ]1

Pruébelo en línea: demostración

Utiliza las mismas ideas de Martin y Peter. En cada paso, divido la cuerda en trozos de longitud 1, trozos de longitud 2, ... Luego los codifico por longitud de rango y utilizo la primera corrida máxima como el siguiente número.

20 bytes con cadenas

t_u+eSmhhrcGd8SlGGQN

Pruébelo en línea: demostración

Combina las ideas de los dos códigos anteriores.

Jakube
fuente
1
Gracias por enseñarme Siempre olvido la ._función y otras funciones útiles en Pyth.
Leaky Nun
Personalmente me gustó más la solución original, pero eh.
clismique
@Jakube Ah. ¿Puedo ver? Si es así, ¡gracias!
clismique
@DerpfacePython Pude jugar golf un byte adicional a mi solución original. También publiqué la solución de codificación de longitud de ejecución basada en Martin, y luego pude combinar los dos enfoques para generar una solución de 20 bytes.
Jakube
5

CJam, 33 31 30 27 bytes

Gracias a Peter Taylor por guardar 1 byte.

1sri({),:)1$W%f/:e`$W=sc+}

Pruébalo aquí.

Explicación

1s      e# Initialise the sequence as "1".
ri(     e# Read input N and decrement.
{       e# For each I from 0 to N-1...
  )     e#   Increment to get I from 1 to N.
  ,     e#   Turn into a range [0 1 ... I-1].
  :)    e#   Increment each element to get [1 2 ... I].
  1$    e#   Copy sequence so far.
  W%    e#   Reverse the copy.
  f/    e#   For each element x in [1 2 ... I], split the (reversed) sequence
        e#   into (non-overlapping) chunks of length x. These are the potentially
        e#   repeated blocks we're looking for. We now want to find the splitting
        e#   which starts with the largest number of equal blocks.
  :e`   e#   To do that, we run-length encode each list blocks.
  $     e#   Then we sort the list of run-length encoded splittings, which primarily
        e#   sorts them by the length of the first run.
  W=    e#   We extract the last splitting which starts with the longest run.
  sc    e#   And then we extract the length of the first run by flattening
        e#   the list into a string and retrieving the first character.
  +     e#   This is the new element of the sequence, so we append it.
}/
Martin Ender
fuente
+1 para :) (5 más para ir ...)
Leaky Nun
5

CJam ( 30 29 27 24 bytes)

'1ri{{)W$W%/e`sc}%$W>+}/

Demostración en línea

Este es un esfuerzo conjunto con Martin.

  • El uso inteligente de la codificación de longitud de ejecución ( e`) para identificar repeticiones es de Martin
  • Así es el uso de W$para simplificar la gestión de la pila
  • Eliminé un par de operaciones de aumento / disminución mediante el uso de $W>+una carcasa especial, como se explica en la disección a continuación.

Mi primer enfoque de 30 bytes:

1ari{,1$f{W%0+_@)</{}#}$W>+}/`

Demostración en línea

Disección

1a        e# Special-case the first term
ri{       e# Read int n and iterate for i=0 to n-1
  ,1$f{   e#   Iterate for j=0 to i-1 a map with extra parameter of the sequence so far
    W%0+  e#     Reverse and append 0 to ensure a non-trivial non-repeating tail
    _@)</ e#     Take the first j+1 elements and split around them
    {}#   e#     Find the index of the first non-empty part from the split
          e#     That's equivalent to the number of times the initial word repeats
  }
  $W>+    e#   Add the maximal value to the sequence
          e#   NB Special case: if i=0 then we're taking the last term of an empty array
          e#   and nothing is appended - hence the 1a at the start of the program
}/
`         e# Format for pretty printing
Peter Taylor
fuente
3

Haskell, 97 bytes

f 1=[1]
f n|x<-f$n-1=last[k|k<-[1..n],p<-[1..n],k*p<n,take(k*p)x==([1..k]>>take p x)]:x
reverse.f

La tercera línea define una función anónima que toma un entero y devuelve una lista de enteros. Véalo en acción.

Explicación

La función auxiliar fconstruye la secuencia en reversa, verificando recursivamente si la secuencia anterior comienza con un bloque repetido. kes el número de repeticiones y pes la longitud del bloque.

f 1=[1]                                   -- Base case: return [1]
f n|x<-f$n-1=                             -- Recursive case; bind f(n-1) to x.
  last[k|k<-[1..n],                       -- Find the greatest element k of [1..n] such that
  p<-[1..n],                              -- there exists a block length p such that
  k*p<n,                                  -- k*p is at most the length of x, and
  take(k*p)x                              -- the prefix of x of length p*k
    ==                                    -- is equal to
  ([1..k]>>take p x)                      -- the prefix of length p repeated k times.
  ]:x                                     -- Insert that k to x, and return the result.
reverse.f                                 -- Composition of reverse and f.
Zgarb
fuente
1

Retina , 66 60 bytes

+1`((\d+)?(?<1>\2)*(?<!\3(?>(?<-1>\3)*)(?!.*\2)(.+)))!
$1$#1

La entrada es un entero unario que se usa !como dígito (aunque eso podría cambiarse a cualquier otro carácter no numérico). La salida es simplemente una cadena de dígitos.

Pruébalo en línea! (Alternativamente, por conveniencia, aquí hay una versión que toma entrada decimal )

Para fines de prueba, esto se puede acelerar mucho con una pequeña modificación, lo que permite probar la entrada 220 en menos de un minuto:

+1`((\d+)?(?<1>\2)*(?=!)(?<!\3(?>(?<-1>\3)*)(?!.*\2)(.+)))!
$1$#1

Pruébalo en línea! ( Versión decimal ) .

Si desea probar números aún más grandes, es mejor alimentarlo con una entrada masiva y poner un :después de la inicial +. Esto hará que Retina imprima la secuencia actual cada vez que termine de calcular un nuevo dígito (con todos los dígitos desactivados por uno).

Explicación

La solución consiste en una única sustitución de expresiones regulares, que se aplica a la entrada repetidamente hasta que el resultado deja de cambiar, lo que en este caso ocurre porque la expresión regular ya no coincide. El +al principio introduce este bucle. El 1es un límite que le dice a Retina que solo reemplace la primera coincidencia (esto solo es relevante para la primera iteración). En cada iteración, la etapa reemplaza una !(desde la izquierda) con el siguiente dígito de la secuencia.

Como de costumbre, si necesita una introducción a los grupos de equilibrio, lo remito a mi respuesta SO .

Aquí hay una versión anotada de la expresión regular. Tenga en cuenta que el objetivo es capturar el número máximo de bloques repetidos en el grupo 1.

(                 # Group 1, this will contain some repeated block at the end
                  # of the existing sequence. We mainly need this so we can
                  # write it back in the substitution. We're also abusing it
                  # for the actual counting but I'll explain that below.
  (\d+)?          # If possible (that is except on the first iteration) capture
                  # one of more digits into group 2. This is a candidate block
                  # which we're checking for maximum repetitions. Note that this
                  # will match the *first* occurrence of the block.
  (?<1>\2)*       # Now we capture as many copies of that block as possible
                  # into group 1. The reason we use group 1 is that this captures
                  # one repetition less than there is in total (because the first
                  # repetition is group 2 itself). Together with the outer
                  # (unrelated) capture of the actual group one, we fix this
                  # off-by-one error. More importantly, this additional capture
                  # from the outer group isn't added until later, such that the
                  # lookbehind which comes next doesn't see it yet, which is
                  # actually very useful.
                  # Before we go into the lookbehind note that at the end of the
                  # regex there's a '!' to ensure that we can actually reach the
                  # end of the string with this repetition of blocks. While this 
                  # isn't actually checked until later, we can essentially assume
                  # that the lookbehind is only relevant if we've actually counted
                  # repetitions of a block at the end of the current sequence.

  (?<!            # We now use a lookbehind to ensure that this is actually the
                  # largest number of repetitions possible. We do this by ensuring
                  # that there is no shorter block which can be matched more
                  # often from the end than the current one. The first time this
                  # is true (since, due to the regex engine's backtracking rules,
                  # we start from longer blocks and move to shorter blocks later),
                  # we know we've found the maximum number of repetitions.
                  # Remember that lookbehinds are matched right-to-left, so
                  # you should read the explanation of the lookbehind from
                  # bottom to top.
    \3            # Try to match *another* occurrence of block 3. If this works,
                  # then this block can be used more often than the current one
                  # and we haven't found the maximum number of repetitions yet.
    (?>           # An atomic group to ensure that we're actually using up all
                  # repetitions from group 1, and don't backtrack.
      (?<-1>\3)*  # For each repetition in group 1, try to match block 3 again.
    )
    (?!.*\2)      # We ensure that this block isn't longer than the candidate
                  # block, by checking that the candidate block doesn't appear
                  # right of it.
    (.+)          # We capture a block from the end into group 3.
  )               # Lookbehind explanation starts here. Read upwards.
)
!                 # As I said above, this ensures that our block actually reaches
                  # the end of the string.

Finalmente, una vez hecho todo esto, reescribimos $1(eliminando así !) el número de capturas en el grupo con el $#1que corresponde al número máximo de repeticiones.

Martin Ender
fuente
¿Por qué Retina toma soluciones unitarias en lugar de números?
clismique
@DerpfacePython Porque es más barato y está permitido por consenso . Puede anular eso especificando que la entrada debe ser un número decimal (en cuyo caso, me complace cambiar la solución).
Martin Ender
Ah, gracias por la aclaración. Sin embargo, solo por curiosidad, ¿puede poner (en los comentarios) una respuesta para decimal? Si es así, gracias.
clismique
@DerpfacePython Se agregaron enlaces separados usando la entrada decimal.
Martin Ender
¿Explicación cuando termine de jugar al golf?
CalculatorFeline
0

Ruby, 84 bytes

La respuesta de Retina me inspiró a hacer una solución basada en expresiones regulares para encontrar la mejor secuencia en lugar de contar de alguna manera las secuencias en una matriz, pero con menos genio (las miradas negativas con cuantificadores no parecen estar permitidas en Ruby, así que dudo Podría portar directamente la respuesta de Retina de todos modos)

->n{s='';n.times{s+=(1..n).map{|i|s=~/(\d{#{i}})\1+$/?$&.size/i: 1}.max.to_s};s[-1]}

Dada una secuencia ya generada s, se asigna sobre todo idesde 1hasta s.length( nse usó en este caso para guardar bytes desde entonces n>=s.length) y luego usa esta expresión regular para ayudar a calcular el número de repeticiones de una subsecuencia con longitud i:

/(.{#{i}})\1+$/
/(                 # Assign the following to group 1
  .{#{i}}          # Match `i` number of characters
         )         # End group 1
          \1+      # Match 1 or more repetitions of group 1
             $/    # Match the end of string

Si se encuentra una coincidencia de esa longitud, calcula el número de repeticiones dividiendo la longitud de la coincidencia dada $&por i, la longitud de la subsecuencia; Si no se encuentra ninguna coincidencia, se trata como 1. La función luego encuentra el número máximo de repeticiones de esta asignación y agrega ese número al final de la cadena.

Tinta de valor
fuente