Redução de Kolakoski


27

visão global

Alguns de vocês podem conhecer a Sequência Kolakoski ( A000002 ), uma sequência autorreferencial bem conhecida que possui a seguinte propriedade:

A propriedade coolio Kolakoski, yo.

É uma sequência que contém apenas 1 e 2 e, para cada grupo de 1 e dois, se você somar o comprimento das execuções, ele será igual a apenas metade do comprimento. Em outras palavras, a sequência de Kolakoski descreve a duração das execuções na própria sequência. É a única sequência que faz isso, exceto a mesma sequência com o 1 inicial excluído. (Isso só é verdade se você se limitar a sequências compostas de 1s e 2s - Martin Ender)


O desafio

O desafio é, dada uma lista de números inteiros:

  • Saída -1se a lista NÃO for um prefixo funcional da sequência Kolakoski.
  • Envie o número de iterações antes que a sequência se torne [2].

O exemplo elaborado

Usando a imagem fornecida como exemplo:

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

Portanto, o número resultante é 8para uma entrada de [1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1].

9 também é bom se você estiver indexando 1.


O Conjunto de Testes (Você também pode testar com sub-iterações)

------------------------------------------+---------
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

Se você está confuso:

Truthy: Chegará a dois sem que nenhum passo intermediário possua outros elementos além de 1e 2. -Einkorn Enchanter 20 hours ago

Falsy: O valor final não é [2]. Os termos intermediários contêm algo diferente do conjunto [1,2]. Algumas outras coisas, veja exemplos.


Este é o , o menor número de bytes será o vencedor.


7
Podemos usar qualquer valor falsey em vez de apenas -1?
mbomb007

1
O que você quer dizer com "NÃO é um prefixo funcional da sequência Kolakoski"? Eu supus que você quis dizer que a lista não chegará [2]até que eu vi o [2,2,1,1,2,1,2]caso de teste.
Ngenisis

1
@ngenisis Chegará a dois sem que nenhuma etapa intermediária possua outros elementos além de 1e 2.
Wheat Wizard

2
Pode ser uma boa ideia adicionar [1]como caso de teste.
Emigna

1
@ mbomb007 qualquer valor distinto é bom. Um número inteiro positivo não está bom. Se você está indexando 1, está tudo bem. "False" está bom. Erro é bom. Qualquer valor de retorno não positivo é bom, mesmo -129.42910.
Magic Octopus Urn

Respostas:


8

Haskell , 126 87 79 76 75 bytes

39 bytes salvos graças a Ørjan Johansen

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

Experimente online!

Este erros na entrada incorreta.


f(e consequentemente !) pode ser muito reduzido usando produção lenta + span/ em lengthvez de acumuladores. Experimente online!
Ørjan Johansen

1
Parece inserir um loop infinito para[1]
Emigna 29/06

1
@Emigna Darn. Custa-me 6 bytes para corrigi-lo, mas eu o corrigi.
Wheat Wizard

@ ØrjanJohansen Isso parece uma boa dica, mas eu não sou proficiente o suficiente em Haskell para entender o que está acontecendo lá. Se você quiser, pode publicá-la como sua própria resposta, mas pelo menos enquanto eu não souber como sua solução funciona, não vou adicioná-la à minha resposta. :)
Assistente de trigo

1
Então eu percebi que este é um caso em que uma importação é realmente mais curto (e também mais simples de entender): import Data.List;f l=length<$>group l. ( <$>é um sinônimo para mapaqui.) Além disso, em vez de ter dois -1casos diferentes , é mais curto usar um @(_:_:_)padrão para forçar o caso principal a corresponder apenas a comprimento> = 2 listas. Experimente online!
Ørjan Johansen

6

05AB1E , 22 bytes

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

Experimente online!

Explicação

[                        # 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

Falha no #[1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,2,1,1]
Weijun Zhou 24/03

@ WeijunZhou: Obrigado, corrigido!
Emigna

Você pode ter se esquecido de atualizar o link ...
Weijun Zhou

1
@WeijunZhou: Na verdade, eu tinha. Obrigado novamente :)
Emigna

3

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

Levei muito tempo ... Mas finalmente terminei!

com 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

Não sei se devo contar os var u=tbytes, considerando que não uso tdurante o algoritmo (a cópia é apenas para obter um modificável, em varvez do parâmetro tconsiderado como val- obrigado ScaLa ). Por favor, diga-me se devo contar.

Difícil o suficiente. Experimente online!

PS: Eu estava pensando em fazê-lo recursivamente, mas terei que passar um contador como parâmetro da verdadeira "subfunção" recursiva; esse fato me faz declarar duas funções, e esses caracteres / bytes nada mais são do que perdidos.

EDIT: Eu tive que mudar (?) Porque não temos certeza se devemos levar em conta [1]. Então, aqui está o 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

Não é otimizado (eu tenho um duplicado "out" para as mesmas condições: quando chego [2]e quando param [2]é tratado separadamente).

NOVO CUSTO = 342 (não modifiquei o título de propósito)


1
Parece inserir um loop infinito para[1]
Emigna 29/17/17

Sim, mas como dito pelo OP (como eu entendi pelo menos): "com o 1 inicial excluído" e "Output o número de iterações antes que a sequência se torne [2]"
V. Courtois

Para meu entendimento, [1]nunca alcança [2]e deve retornar -1 .
Emigna

Entendo. Então você acha que eu deveria colocar uma condição pequena no começo? Obrigado pelo teu conselho.
V. Courtois

Não conheço scala, mas presumo que você possa modificar o loop para parar quando o comprimento da lista for menor que 2. Você já parece ter verificado se o elemento é 2 no final.
Emigna

2

JavaScript, 146 142 bytes

Primeira tentativa no código de golfe, parece que o "retorno" na função maior é bastante tedioso ...

Além disso, a verificação de b = 1 eb = 2 ocupa alguns bytes ...

Aqui está o 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}

Explicação

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

Dados de teste (usando os dados de teste fornecidos)

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]

Edit 1: 146 -> 142: Revogando minha edição na redução de bytes, porque isso afeta a saída; e algumas edições na última declaração


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}salva 5 bytes (para loop em vez de while; vírgulas vs chaves; && vs if). Você pode usar o compilador fechamento do google ( closure-compiler.appspot.com ) para obter estas otimizações feitas para você
Oki

2

Gelatina ,26 25 22 21 20 bytes

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

Experimente online!

Na verdade, esse código não estava funcionando corretamente até 20 bytes e eu nem percebi; estava falhando no [2,2]caso de teste. Deve funcionar perfeitamente agora.


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)

Indexado a 0. Joga "ReferenceError: X is not defined"e "InternalError: too much recursion"com entrada ruim.

Casos de teste


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))))))

Um básico loopcom uma pré-verificação em casos extremos. Retorna nilpara entradas inválidas. Eu não sabia (= [2] '(2))é true: o


1

Python 2, 146 bytes (somente função)

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)

Retorna 0 na entrada falsa (ok, pois é indexada em 1). Simplesmente use-o assim:

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

1

Mathematica, 82 bytes

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

Functionque substitui repetidamente {2}pelo símbolo indefinido T, uma lista de (um ou mais) 1s e 2a próxima iteração e qualquer outra coisa 0até que um ponto fixo seja alcançado, em seguida, retorna FirstPositiono símbolo Tno FixedPointListmenos resultante 1. A saída é {n}onde nestá o 1número ( indexado) de iterações necessárias para alcançar {2}o caso -1+Missing["NotFound"]de verdade e o caso de falsidade.

Se a saída tiver que ser em nvez de {n}, custa mais três bytes:

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

1

Python 2 , 184 163 156 bytes

  • @Felipe Nardi Batista economizou 21 bytes !!!! Muito obrigado!!!!
  • Halvard Hummel economizou 7 bytes !! obrigado

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

Experimente online!

Explicação:

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 



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)

Experimente online!

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)

Experimente online!

Explicação

Uma nova sequência (w) é inicializada para armazenar a próxima iteração da redução. Um contador (c) é inicializado para acompanhar o número de iterações.

Cada item nas seqüências originais é comparado ao valor anterior. Se forem iguais, o valor do último item de (w) será aumentado com 1. Se forem diferentes, a sequência (w) será estendida com [1].

Se w == [2], o contador (c) é retornado. Senão, se a (s) sequência (s) original (ais) contiverem outros itens além de 1 e 2, um valor -1 será retornado. Caso contrário, a função é chamada recursivamente com a nova sequência (w) como (s) e o contador (c) aumentado em 1.


Para salvar um byte, estou tentando combinar as duas primeiras linhas def f(s,c=2,j=0,w=[1]):, mas isso gera um resultado diferente. Alguém poderia explicar por que isso é?
Jitse 24/07


@JoKing Isso faz todo o sentido, obrigado!
Jitse 24/07

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

Passa em todos os casos de teste. Lança um ou mais erros caso contrário. Eu odeio verificações de validade; esse código poderia ter sido tão útil se as entradas fossem boas; seria mais curto, mesmo que a entrada fosse uma sequência de 1 e 2, não necessariamente um prefixo da sequência de Kolakoski. Aqui, temos que verificar o vetor inicial (caso contrário, o caso de teste [-2,1]) teria passado) e o vetor resultante (caso contrário [1,1,1], teria passado).


0

Ruby , 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}

Experimente online!

Editar: salvou 4 bytes convertendo para lambda recursiva.

Retorna o número indexado de 1 de iterações ou 0 como falsey.

Utiliza o método chunk do enumerável Ruby, que faz exatamente o que precisamos: agrupando execuções consecutivas de números idênticos. Os comprimentos das execuções constituem a matriz para a próxima iteração. Mantém a iteração enquanto a matriz tem mais de 1 elemento e nenhum número diferente de 1 e 2 foi encontrado.


0

Pitão , 45 bytes

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

Experimente online!

Provavelmente ainda é possível jogar golfe. É definitivamente jogável se .?funcionou da maneira que eu esperava que fosse (sendo uma elsepara a estrutura mais interna, em vez da mais 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

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.