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.