Reducción de Kolakoski

27

Visión general

Algunos de ustedes podrían estar al tanto de la secuencia de Kolakoski ( A000002 ), una secuencia autorreferencial bien conocida que tiene la siguiente propiedad:

La propiedad coolio Kolakoski, yo.

Es una secuencia que contiene solo 1 y 2, y para cada grupo de 1 y dos, si suma la longitud de las carreras, es igual a sí misma, solo la mitad de la longitud. En otras palabras, la secuencia de Kolakoski describe la longitud de las corridas en la secuencia misma. Es la única secuencia que hace esto, excepto la misma secuencia con el 1 inicial eliminado. (Esto solo es cierto si te limitas a secuencias compuestas de 1s y 2s - Martin Ender)


El reto

El desafío es, dada una lista de enteros:

  • Salida -1si la lista NO es un prefijo de trabajo de la secuencia de Kolakoski.
  • Salida el número de iteraciones antes de la secuencia se vuelve [2].

El ejemplo resuelto

Usando la imagen proporcionada como ejemplo:

[1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1] # Iteration 0 (the input).
[1,2,2,1,1,2,1,2,2,1,2]             # Iteration 1.
[1,2,2,1,1,2,1,1]                   # Iteration 2.
[1,2,2,1,2]                         # Iteration 3.
[1,2,1,1]                           # Iteration 4.
[1,1,2]                             # Iteration 5.
[2,1]                               # Iteration 6.
[1,1]                               # Iteration 7.
[2]                                 # Iteration 8.

Por lo tanto, el número resultante es 8para una entrada de [1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1].

9 también está bien si está indexando 1.


The Test Suite (también puedes probar con sub iteraciones)

------------------------------------------+---------
Truthy Scenarios                          | Output
------------------------------------------+---------
[1,1]                                     | 1 or 2
[1,2,2,1,1,2,1,2,2,1]                     | 6 or 7
[1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1]       | 8 or 9
[1,2]                                     | 2 or 3
------------------------------------------+---------
Falsy Scenarios                           | Output
------------------------------------------+---------
[4,2,-2,1,0,3928,102904]                  | -1 or a unique falsy output.
[1,1,1]                                   | -1
[2,2,1,1,2,1,2] (Results in [2,3] @ i3)   | -1 (Trickiest example)
[]                                        | -1
[1]                                       | -1

Si estás confundido:

Verdad: Eventualmente llegará a dos sin ningún paso intermedio que tenga elementos que no sean 1y 2. -Einkorn Enchanter 20 hours ago

Falsy: el valor final no lo es [2]. Los términos intermedios contienen algo más que algo del conjunto [1,2]. Un par de otras cosas, ver ejemplos.


Este es el , el conteo de bytes más bajo será el vencedor.

Urna de pulpo mágico
fuente
77
¿Podemos usar cualquier valor de falsey en lugar de solo -1?
mbomb007
1
¿Qué quiere decir con "NO un prefijo de trabajo de la secuencia de Kolakoski"? Asumí que querías decir que la lista no llega [2]hasta que vi el [2,2,1,1,2,1,2]caso de prueba.
ngenisis
1
@ngenisis Eventualmente llegará a dos sin ningún paso intermedio que tenga elementos distintos de 1y 2.
Wheat Wizard
2
Puede ser una buena idea agregar [1]como un caso de prueba.
Emigna
1
@ mbomb007 cualquier valor distinto está bien. Un entero positivo no está bien. Si estás indexando 1, 0 está bien. "Falso" está bien. El error está bien. Cualquier valor de retorno no positivo está bien, incluso -129.42910.
Urna mágica del pulpo

Respuestas:

8

Haskell , 126 87 79 76 75 bytes

39 bytes guardados gracias a Ørjan Johansen

import Data.List
f[2]=0
f y@(_:_:_)|all(`elem`[1,2])y=1+f(length<$>group y)

Pruébalo en línea!

Este error en la entrada incorrecta.

Asistente de trigo
fuente
f(y, en consecuencia !) se puede acortar mucho usando producción perezosa + span/ en lengthlugar de acumuladores. Pruébalo en línea!
Ørjan Johansen
1
Parece entrar en un bucle infinito para[1]
Emigna
1
@Emigna Darn. Me cuesta 6 bytes arreglarlo, pero lo he arreglado.
Wheat Wizard
@ ØrjanJohansen Eso parece un buen consejo, pero no soy lo suficientemente competente en Haskell para entender qué está pasando allí. Si lo desea, puede publicarlo como su propia respuesta, pero al menos mientras no sepa cómo funciona su solución, no la agregaré a mi respuesta. :)
Wheat Wizard
1
Entonces me di cuenta que este es un caso en el que una importación es en realidad más corto (y también más fácil de entender): import Data.List;f l=length<$>group l. ( <$>es sinónimo de mapaquí). Además, en lugar de tener dos -1casos diferentes , es más corto usar un @(_:_:_)patrón para forzar que el caso principal solo coincida con listas de longitud> = 2. Pruébalo en línea!
Ørjan Johansen
6

05AB1E , 22 bytes

[Dg2‹#γ€gM2›iX]2QJiNë®

Pruébalo en línea!

Explicación

[                        # start a loop
 D                       # duplicate current list
  g2‹#                   # break if the length is less than 2
      γ                  # group into runs of consecutive equal elements
       €g                # get length of each run
         M2›iX           # if the maximum run-length is greater than 2, push 1
              ]          # end loop
               2QJi      # if the result is a list containing only 2
                   N     # push the iteration counter from the loop
                    ë®   # else, push -1
                         # implicitly output top of stack
Emigna
fuente
Falla para[1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,2,1,1]
Weijun Zhou
@WeijunZhou: ¡Gracias, arreglado!
Emigna
Es posible que haya olvidado actualizar el enlace ...
Weijun Zhou
1
@WeijunZhou: De hecho, lo hice. Gracias de nuevo :)
Emigna
3

SCALA, 290 (282?) Caracteres, 290 (282?) Bytes

Me tomó muuucho tiempo ... ¡Pero finalmente terminé!

con este código:

var u=t
var v=Array[Int]()
var c= -1
var b=1
if(!u.isEmpty){while(u.forall(x=>x==1|x==2)){c+=1
if(u.size>1){var p=u.size-1
for(i<-0 to p){if(b==1){var k=u(i)
v:+=(if(i==p)1 else if(u(i+1)==k){b=0
if(p-i>1&&u(i+2)==k)return-1
2}else 1)} else b=1}
u=v
v=v.take(0)}else if(u(0)==2)return c}}
c

No sé si debería contarlos var u=ten los bytes, teniendo en cuenta que no los uso tdurante el algoritmo (la copia es solo para obtener un modificable en varlugar del parámetro tconsiderado comoval - gracias ScaLa ). Por favor, dime si debo contarlo.

Suficientemente difícil. Pruébalo en línea!

PD: Estaba pensando en hacerlo de forma recursiva, pero tendré que pasar un contador como parámetro de la verdadera "subfunción" recursiva; Este hecho me hace declarar dos funciones, y estos caracteres / bytes no son más que perdidos.

EDITAR: Tuve que cambiar (?) Porque no estamos seguros de que deberíamos tomar en cuenta el [1]caso. Así que aquí está el código modificado:

var u=t
var v=Array[Int]()
var c= -1
var b=1
if(!u.isEmpty){try{t(1)}catch{case _=>return if(t(0)==2)0 else -1}
while(u.forall(x=>x==1|x==2)){c+=1
if(u.size>1){var p=u.size-1
for(i<-0 to p){if(b==1){var k=u(i)
v:+=(if(i==p)1 else if(u(i+1)==k){b=0
if(p-i>1&&u(i+2)==k)return-1
2}else 1)} else b=1}
u=v
v=v.take(0)}else if(u(0)==2)return c}}
c

No está optimizado (tengo un "out" duplicado para las mismas condiciones: cuando llego [2]y cuando param es[2] se trata por separado).

NUEVO COSTO = 342 (no modifiqué el título a propósito)

V. Courtois
fuente
1
Parece entrar en un bucle infinito para[1]
Emigna
Sí, pero como lo dijo el OP (como entendí al menos): "con el 1 inicial eliminado" y "Mostrar el número de iteraciones antes de que la secuencia se convierta [2]"
V. Courtois
A mi entender, [1]nunca alcanza [2]y por lo tanto debería devolver -1 .
Emigna
Veo. Entonces, ¿crees que debería poner una pequeña condición al comienzo? Gracias por su consejo.
V. Courtois
No conozco scala, pero supongo que puede modificar el ciclo para que se detenga cuando la longitud de la lista sea menor que 2. Parece que ya tiene la verificación de que el elemento es 2 al final.
Emigna
2

JavaScript, 146 142 bytes

Primero intente en golf de código, parece que el "retorno" en la función más grande es bastante tedioso ...

Además, la comprobación de b = 1 y b = 2 ocupa algunos bytes ...

Aquí está el código:

f=y=>{i=t=!y[0];while(y[1]){r=[];c=j=0;y.map(b=>{t|=b-1&&b-2;if(b-c){if(j>0)r.push(j);c=b;j=0}j++});(y=r).push(j);i++}return t||y[0]-2?-1:0^i}

Explicación

f=y=>{/*1*/}                                        //function definition

//Inside /*1*/:
  i=t=!y[0];                                        //initialization
                                                    //if the first one is 0 or undefined, 
                                                    //set t=1 so that it will return -1   
                                                    //eventually, otherwise i=0
  while(y[1]){/*2*/}                                //if there are 2+ items, start the loop

  //Inside /*2*/:
    r=[];c=j=0;                                     //initialization
    y.map(b=>{/*3*/});                              //another function definition

    //Inside /*3*/:
      t|=b-1&&b-2;                                  //if b==1 or b==2, set t=1 so that the
                                                    //entire function returns -1
      if(b-c){if(j>0)r.push(j);c=b;j=0}             //if b!=c, and j!=0, then push the 
                                                    //count to the array and reset counter
      j++                                           //counting duplicate numbers

    (y=r).push(j);i++                               //push the remaining count to the array
                                                    //and proceed to another stage

  return t||y[0]-2?-1:0^i                           //if the remaining element is not 2, or
                                                    //t==1 (means falsy), return -1,
                                                    //otherwise return the counter i

Datos de prueba (usando los datos de prueba dados)

l=[[1,1],[1,2,2,1,1,2,1,2,2,1],[1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1],[1,2],[4,2,-2,1,0,3928,102904],[1,1,1],[2,2,1,1,2,1,2],[]];
console.log(l.map(f));
//Output: (8) [1, 6, 8, 2, -1, -1, -1, -1]

Edición 1: 146 -> 142: Revocación de mi edición para reducir bytes, porque esto afecta la salida; y alguna edición en la última declaración

usuario71543
fuente
f=a=>{for(i=t=!a[0];a[1];)r=[],c=j=0,a.map(a=>{t|=a-1&&a-2;a-c&&(0<j&&r.push(j),c=a,j=0);j++}),(a=r).push(j),i++;return t||a[0]-2?-1:0^i}ahorra 5 bytes (para bucle en lugar de while; comas vs llaves; && vs if). Puede usar el compilador de cierre de google ( clos-compiler.appspot.com ) para hacer estas optimizaciones por usted
Oki
2

Jalea ,26 25 22 21 20 bytes

FQœ-2R¤
ŒgL€µÐĿṖ-LÇ?

Pruébalo en línea!

Este código en realidad no funcionaba correctamente hasta 20 bytes y ni siquiera me di cuenta; estaba fallando en el [2,2]caso de prueba. Debería funcionar perfectamente ahora.

dispersión
fuente
2

JavaScript (ES6), 127 126 95 80 bytes

g=(a,i,p,b=[])=>a.map(x=>3>x&0<x?(x==p?b[0]++:b=[1,...b],p=x):H)==2?i:g(b,~~i+1)

0 indexado. Lanza "ReferenceError: X is not defined"y "InternalError: too much recursion"en mal aporte.

Casos de prueba

Oki
fuente
1

Clojure, 110 bytes

#(if-not(#{[][1]}%)(loop[c % i 0](if(every? #{1 2}c)(if(=[2]c)i(recur(map count(partition-by + c))(inc i))))))

Un básico loopcon una verificación previa en casos extremos. Devoluciones nilpara entradas inválidas. No sabía (= [2] '(2))es true: o

NikoNyrh
fuente
1

Python 2, 146 bytes (solo función)

f=lambda l,i=0:i if l==[1]else 0if max(l)>2or min(l)<1else f([len(x)+1for x in"".join(`v!=l[i+1]`[0]for i,v in enumerate(l[:-1])).split("T")],i+1)

Devuelve 0 en la entrada falsa (está bien ya que está indexado en 1) Simplemente utilízalo así:

print(f([1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1]))
erik
fuente
1

Mathematica, 82 bytes

FixedPointList[#/.{{2}->T,{(1|2)..}:>Length/@Split@#,_->0}&,#]~FirstPosition~T-1&

Functionque reemplaza repetidamente {2}con el símbolo indefinido T, una lista de (uno o más) 1sys 2con la siguiente iteración, y cualquier otra cosa 0hasta que se alcanza un punto fijo, luego devuelve FirstPositionel símbolo Ten el FixedPointListsigno negativo resultante 1. La salida es {n}donde nestá el número ( 1indexado) de iteraciones necesarias para alcanzar {2}el caso verdadero y -1+Missing["NotFound"]el caso falso.

Si la salida debe ser en nlugar de {n}, cuesta tres bytes más:

Position[FixedPointList[#/.{{2}->T,{(1|2)..}:>Length/@Split@#,_->0}&,#],T][[1,1]]-1&
ngenisis
fuente
1

Python 2 , 184 163 156 bytes

  • @Felipe Nardi Batista ahorró 21 bytes !!!! ¡¡¡¡muchas gracias!!!!
  • ¡Halvard Hummel ahorró 7 bytes! Gracias

Python 2 , 156 bytes

a,c=input(),0
t=a==[]
while 1<len(a)and~-t:
 r,i=[],0
 while i<len(a):
	j=i
	while[a[j]]==a[i:i+1]:i+=1
	r+=[i-j]
 a=r;c+=1;t=any(x>2for x in a)
print~c*t+c

Pruébalo en línea!

Explicación:

a,c=input(),0                             #input and initialize main-counter 

t=a==[]                                   #set t to 1 if list's empty. 

while len(a)>1:                           #loop until list's length is 1.

 r,i=[],0                                 #Initialize temp. list and 
                                          #list-element-pointer 

 while i<len(a):                          #loop for the element in list 

  j=0                                     #set consecutive-item-counter to 0   

  while(i+j)<len(a)and a[i]==a[i+j]:j+=1  #increase the consec.-counter

  r+=[j];i+=j                             #add the value to a list, move the 
                                          #list-element-pointer 

 a=r;c+=1;t=any(x>2for x in a)            #update the main list, increase t 
                                          #the counter, check if any number 
 if t:break;                              #exceeds 2 (if yes, exit the loop)

print[c,-1][t]                            #print -1 if t or else the 
                                          #counter's 
                                          #value 
officialaimm
fuente
1
156 bytes
Halvard Hummel
1

Python 2 , 122 bytes

def f(s,c=2,j=0):
 w=[1]
 for i in s[1:]:w+=[1]*(i!=s[j]);w[-1]+=i==s[j];j+=1
 return(w==[2])*c-({1,2}!=set(s))or f(w,c+1)

Pruébalo en línea!

Python 3 , 120 bytes

def f(s,c=2,j=0):
 w=[1]
 for i in s[1:]:w+=[1]*(i!=s[j]);w[-1]+=i==s[j];j+=1
 return(w==[2])*c-({1,2}!={*s})or f(w,c+1)

Pruébalo en línea!

Explicación

Se inicia una nueva secuencia (w) para almacenar la próxima iteración de la reducción. Se inicializa un contador (c) para realizar un seguimiento del número de iteraciones.

Cada elemento de la secuencia o secuencias originales se compara con el valor anterior. Si son iguales, el valor del último elemento de (w) aumenta con 1. Si son diferentes, la secuencia (w) se extiende con [1].

Si w == [2], se devuelve el contador (c). De lo contrario, si la secuencia o secuencias originales contienen otros elementos que no sean 1 y 2, se devuelve un valor -1. Si ninguno de los dos es el caso, la función se llama recursivamente con la nueva secuencia (w) como (s) y el contador (c) se incrementa en 1.

Jitse
fuente
Para guardar un byte, estoy tratando de combinar las dos primeras líneas def f(s,c=2,j=0,w=[1]):, pero eso da un resultado diferente. ¿Alguien podría explicar por qué es eso?
Jitse
@JoKing Eso tiene mucho sentido, ¡gracias!
Jitse
0

R, 122 bytes

a=scan()
i=0
f=function(x)if(!all(x%in%c(1,2)))stop()
while(length(a)>1){f(a)
a=rle(a)$l
f(a)
i=i+1}
if(a==2)i else stop()

Pasa todos los casos de prueba. Lanza uno o más errores de lo contrario. Odio los controles de validez; este código podría haber sido tan útil si las entradas fueran agradables; sería más corto incluso en el caso de que la entrada fuera una secuencia de 1 y 2, no necesariamente un prefijo de la secuencia de Kolakoski. Aquí, tenemos que verificar tanto el vector inicial (de lo contrario, el caso de prueba [-2,1]) habría pasado) como el vector resultante (de lo contrario [1,1,1], habría pasado).

Andreï Kostyrka
fuente
0

Rubí , 81 77 bytes

f=->a,i=1{a[1]&&a-[1,2]==[]?f[a.chunk{|x|x}.map{|x,y|y.size},i+1]:a==[2]?i:0}

Pruébalo en línea!

Editar: guardado 4 bytes al convertir a lambda recursiva.

Devuelve 1 número indexado de iteraciones o 0 como falsey.

Utiliza el método fragmentado de Ruby enumerable, que hace exactamente lo que necesitamos: agrupar series consecutivas de números idénticos. Las longitudes de las ejecuciones constituyen la matriz para la próxima iteración. Sigue iterando mientras la matriz tiene más de 1 elemento y no se han encontrado otros números que no sean 1 y 2.

Kirill L.
fuente
0

Pyth , 45 bytes

L?||qb]1!lb-{b,1 2_1?q]2b1Z.V0IKy~QhMrQ8*KhbB

Pruébalo en línea!

Esto probablemente todavía sea golfable. Definitivamente es golfable si .?funciona de la manera que esperaba (siendo elsepara la estructura más interna en lugar de la más externa)

L?||qb]1!lb-{b,1 2_1?q]2b1Z # A lambda function for testing an iteration of the shortening
L                           # y=lambda b:
 ?                          # if
    qb]1                    #    b == [1]
   |    !lb                 #      or !len(b)
  |         {b              #        or b.deduplicate()
           -  ,1 2          #             .difference([1,2]):
                  _1        #               return -1
                    ?q]2b1Z # else: return 1 if [2] == b else Z (=0)

.V0                         # for b in range(0,infinity):
   IKy~Q                    # if K:=y(Q :=        (applies y to old value of Q)
        hM                  #    map(_[0],
          rQ8               #               run_length_encode(Q)):
             *Khb           #    print(K*(b+1))
                 B          #    break
ar4093
fuente
0

Perl 5 -p , 71 bytes

$_.=$";s/(. )\1*/$&=~y|12||.$"/ge&$.++while/^([12] ){2,}$/;$_=/^2 $/*$.

Pruébalo en línea!

1-indexado. Salidas 0para falsedad.

Xcali
fuente