Redukcja Kolakoski


27

Przegląd

Niektórzy z was mogą znać Sekwencję Kolakoskiego ( A000002 ), dobrze znaną autoreferencyjną sekwencję, która ma następującą właściwość:

Coolio Kolakoski, yo.

Jest to sekwencja zawierająca tylko 1 i 2, a dla każdej grupy 1 i 2, jeśli dodasz długość serii, będzie ona równa się tylko połowie długości. Innymi słowy, sekwencja Kolakoski opisuje długość serii w samej sekwencji. Jest to jedyna sekwencja, która to robi, z wyjątkiem tej samej sekwencji z początkowym 1 usuniętym. (Jest to prawdą tylko wtedy, gdy ograniczysz się do sekwencji składających się z 1 i 2 sekund - Martin Ender)


Wyzwanie

Wyzwaniem jest, biorąc pod uwagę listę liczb całkowitych:

  • Dane wyjściowe, -1jeśli lista NIE jest działającym prefiksem sekwencji Kolakoski.
  • Podaj liczbę iteracji zanim sekwencja stanie się [2].

Opracowany przykład

Wykorzystując dostarczony obraz jako przykład:

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

Dlatego wynikowa liczba służy 8do wprowadzenia [1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1].

9 jest również w porządku, jeśli indeksujesz 1.


Pakiet testowy (możesz również testować z pod-iteracjami)

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

Jeśli jesteś zdezorientowany:

Prawda: ostatecznie osiągnie dwa bez żadnego pośredniego kroku mającego elementy inne niż 1i 2. -Einkorn Enchanter 20 hours ago

Falsy: Wartość końcowa nie jest [2]. Warunki pośrednie zawierają coś innego niż coś z zestawu [1,2]. Kilka innych rzeczy, patrz przykłady.


To jest , zwycięzcą będzie najniższa liczba bajtów.


7
Czy możemy użyć dowolnej wartości falsey zamiast po prostu -1?
mbomb007

1
Co rozumiesz przez „NIE działający prefiks sekwencji Kolakoski”? Zakładałem, że masz na myśli, że lista ostatecznie nie osiąga, [2]dopóki nie zobaczyłem [2,2,1,1,2,1,2]przypadku testowego.
ngenisis

1
@ngenisis W końcu osiągnie dwa bez żadnego pośredniego kroku mającego elementy inne niż 1i 2.
Wheat Wizard

2
Może być dobrym pomysłem, aby dodać [1]jako przypadek testowy.
Emigna

1
@ mbomb007 każda wyraźna wartość jest w porządku. Dodatnia liczba całkowita nie jest w porządku. Jeśli indeksujesz 1, 0 jest w porządku. „Fałsz” jest w porządku. Błąd jest w porządku. Każda dodatnia wartość zwrotu jest w porządku, nawet -129,42910.
Magic Octopus Urn

Odpowiedzi:


8

Haskell , 126 87 79 76 75 bajtów

39 bajtów zaoszczędzonych dzięki Ørjanowi Johansenowi

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

Wypróbuj online!

To błędy przy złych danych wejściowych.


f(i w konsekwencji !) można znacznie skrócić, używając leniwej produkcji + span/ lengthzamiast akumulatorów. Wypróbuj online!
Ørjan Johansen

1
Wydaje się, że wchodzi w nieskończoną pętlę dla[1]
Emigna

1
@Emigna Darn. Naprawienie go kosztuje 6 bajtów, ale naprawiłem to.
Wheat Wizard

@ ØrjanJohansen To wydaje się być dobrą wskazówką, ale nie jestem wystarczająco biegły w Haskell, aby zrozumieć, co się tam dzieje. Jeśli chcesz, możesz napisać to jako własną odpowiedź, ale przynajmniej dopóki nie wiem, jak działa twoje rozwiązanie, nie dodam go do mojej odpowiedzi. :)
Wheat Wizard

1
Później zrozumiałem, że jest to przypadek, gdy import jest rzeczywiście krótsza (a także prostsze do zrozumienia) import Data.List;f l=length<$>group l. ( <$>jest tutaj synonimem map). Zamiast dwóch różnych -1przypadków, krótsze jest użycie @(_:_:_)wzorca, aby zmusić główny przypadek tylko do dopasowania długości> = 2 list. Wypróbuj online!
Ørjan Johansen

6

05AB1E , 22 bajty

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

Wypróbuj online!

Wyjaśnienie

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

Nie powiedzie się za[1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,2,1,1]
Weijun Zhou,

@WeijunZhou: Dzięki, naprawiono!
Emigna

Być może zapomniałeś zaktualizować link ...
Weijun Zhou

1
@WeijunZhou: Rzeczywiście miałem.
Jeszcze

3

SCALA, 290 (282 a) znaków, 290 (282 a) bajtów

Zajęło mi to bardzo długo ... Ale w końcu skończyłem!

z tym kodem:

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

Nie wiem, czy powinienem policzyć var u=tbajty, biorąc pod uwagę, że nie używam tpodczas algorytmu (kopia ma tylko modyfikować varzamiast parametru tuważanego za val- dzięki ScaLa ). Powiedz mi, czy powinienem to policzyć.

Wystarczająco trudne. Wypróbuj online!

PS: Myślałem o zrobieniu tego rekurencyjnie, ale będę musiał przekazać licznik jako parametr prawdziwej rekurencyjnej „podfunkcji”; fakt ten każe mi zadeklarować dwie funkcje, a te znaki / bajty są niczym innym jak zagubionym.

EDYCJA: Musiałem zmienić (?), Ponieważ nie jesteśmy pewni, czy powinniśmy brać pod uwagę [1]przypadki. Więc tutaj jest zmodyfikowany kod:

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

Nie jest zoptymalizowany (mam duplikat „out” dla tych samych warunków: [2]kiedy dojdę i kiedy parametr [2]jest traktowany osobno).

NOWY KOSZT = 342 (Celowo nie zmodyfikowałem tytułu)


1
Wydaje się, że wchodzi w nieskończoną pętlę dla[1]
Emigna

Tak, ale jak powiedział OP (co zrozumiałem przynajmniej): „z usuniętą początkową 1” i „Wypisuj liczbę iteracji, zanim sekwencja stanie się [2]
V. Courtois

W moim rozumieniu [1]nigdy nie dociera [2]i dlatego powinien powrócić -1 .
Emigna

Widzę. Więc myślisz, że powinienem postawić mały warunek na początku? Dzięki za radę.
V. Courtois

Nie znam Scali, ale zakładam, że możesz po prostu zmodyfikować pętlę, aby zatrzymać, gdy długość listy jest mniejsza niż 2. Wydaje się, że już masz kontrolę, że element ma 2 na końcu.
Emigna

2

JavaScript, 146 142 bajtów

Pierwsza próba gry w golfa wydaje się, że „powrót” w większej funkcji jest dość nużący ...

Ponadto sprawdzenie b = 1 i b = 2 zajmuje kilka bajtów ...

Oto kod:

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}

Wyjaśnienie

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

Dane testowe (przy użyciu danych testowych)

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]

Edycja 1: 146 -> 142: Cofam moją edycję po zmniejszeniu bajtów, ponieważ wpływa to na wynik; i trochę edycji ostatniego zdania


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}zapisuje 5 bajtów (dla pętli zamiast while; przecinki vs. nawiasy klamrowe; && vs if). Możesz użyć kompilatora zamykającego Google ( closure-compiler.appspot.com ), aby wykonać te optymalizacje za Ciebie
Oki

2

Galaretka ,26 25 22 21 20 bajtów

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

Wypróbuj online!

Ten kod faktycznie nie działał poprawnie do 20 bajtów, a ja nawet nie zauważyłem; zawiodło w [2,2]przypadku testowym. Powinien teraz działać idealnie.


2

JavaScript (ES6), 127 126 95 80 bajtów

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-indeksowane. Rzuty "ReferenceError: X is not defined"i "InternalError: too much recursion"przy złym wejściu.

Przypadki testowe


1

Clojure, 110 bajtów

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

Podstawowy loopz wstępną kontrolą skrzynek na brzeg. Zwraca nilza nieprawidłowe dane wejściowe. I nie wiem, (= [2] '(2))jest true: o


1

Python 2, 146 bajtów (tylko funkcja)

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)

Zwraca 0 na wejściu falsy (ok, ponieważ jest indeksowane 1). Po prostu użyj go w następujący sposób:

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

1

Mathematica, 82 bajty

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

Functionktóry wielokrotnie zastępuje {2}niezdefiniowany symbol T, listę (jednego lub więcej) 1si 2z następną iteracją, i wszystko inne z 0aż do osiągnięcia stałego punktu, a następnie zwraca FirstPositionsymbol Tw wynikowym FixedPointListminusie 1. Dane wyjściowe to, {n}gdzie n( 1-indexed) liczba iteracji potrzebnych do sięgnięcia {2}po przypadek prawdy i -1+Missing["NotFound"]przypadek fałszowania.

Jeśli wyjście musi być nzamiast {n}, kosztuje trzy kolejne bajty:

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

1

Python 2 , 184 163 156 bajtów

  • @Felipe Nardi Batista zapisał 21 bajtów !!!! wielkie dzięki!!!!
  • Halvard Hummel zapisał 7 bajtów !! dzięki

Python 2 , 156 bajtów

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

Wypróbuj online!

Wyjaśnienie:

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 bajty

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)

Wypróbuj online!

Python 3 , 120 bajtów

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)

Wypróbuj online!

Wyjaśnienie

Inicjowana jest nowa sekwencja (w), aby zapisać następną iterację redukcji. Licznik (c) jest inicjowany w celu śledzenia liczby iteracji.

Każdy element w oryginalnej sekwencji (sekwencjach) jest porównywany z poprzednią wartością. Jeśli są takie same, wartość ostatniego elementu (w) zwiększa się o 1. Jeśli są różne, kolejność (w) jest przedłużana o [1].

Jeśli w == [2], zwracany jest licznik (c). W przeciwnym razie, jeśli oryginalna sekwencja (sekwencje) zawiera inne elementy niż 1 i 2, zwracana jest wartość -1. Jeśli tak nie jest, funkcja jest wywoływana rekurencyjnie z nową sekwencją (w) as (s), a licznik (c) zwiększony o 1.


Aby zapisać bajt, próbuję połączyć pierwsze dwie linie def f(s,c=2,j=0,w=[1]):, ale daje to inny wynik. Czy ktoś mógłby wyjaśnić, dlaczego tak jest?
Jitse


@JoKing To ma sens, dziękuję!
Jitse

0

R, 122 bajty

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

Przechodzi wszystkie przypadki testowe. W przeciwnym razie zgłasza jeden lub więcej błędów. Nienawidzę kontroli ważności; ten kod mógłby być tak golfistowany, gdyby dane wejściowe były dobre; byłby krótszy, nawet gdyby dane wejściowe były sekwencją 1 i 2, niekoniecznie przedrostkiem sekwencji Kolakoski. Tutaj musimy sprawdzić zarówno wektor początkowy (inaczej przypadek testowy [-2,1]) minąłby), a wektor wynikowy (inaczej [1,1,1]by minął).


0

Ruby , 81 77 bajtów

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}

Wypróbuj online!

Edycja: Zapisano 4 bajty, konwertując na rekurencyjną lambda.

Zwraca 1 indeksowaną liczbę iteracji lub 0 jako falsey.

Wykorzystuje metodę fragmentaryczną Ruby enumerable, która robi dokładnie to, czego potrzebujemy - grupując kolejne serie identycznych liczb. Długości przebiegów stanowią tablicę dla następnej iteracji. Powtarza iterację, gdy tablica jest dłuższa niż 1 element i nie napotkano żadnych liczb innych niż 1 i 2.


0

Pyth , 45 bajtów

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

Wypróbuj online!

Jest to prawdopodobnie wciąż gra w golfa. Zdecydowanie nadaje się do gry w golfa, jeśli działałby .?tak, jak chciałem (jest to elsekonstrukcja najbardziej wewnętrzna zamiast najbardziej zewnętrznej)

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.