Скорочення Колакоскі


27

Огляд

Деякі з вас, можливо, знають про послідовність Колакоскі ( A000002 ), добре відому самореференційну послідовність, яка має таке властивість:

Власність Coolio Kolakoski, рік.

Це послідовність, що містить лише 1 і 2, і для кожної групи 1 і 2, якщо додати тривалість пробіжок, вона дорівнює самій, лише половині довжини. Іншими словами, послідовність Колакоскі описує тривалість пробігів у самій послідовності. Це єдина послідовність, яка робить це, за винятком тієї ж послідовності, що була видалена 1. (Це справедливо лише в тому випадку, якщо ви обмежитеся послідовностями, що складаються з 1 та 2 - Мартін Ендер)


Змагання

Завдання полягає в тому, щоб отримати список цілих чисел:

  • Виведіть, -1якщо список НЕ є робочим префіксом послідовності Колакоскі.
  • Виведіть кількість ітерацій до настання послідовності [2].

Приклад відпрацьованого

Використовуючи поданий образ як приклад:

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

Отже, отримане число призначене 8для введення [1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1].

9 також добре, якщо ви здійснюєте 1-індексацію.


Тестовий набір (Ви можете протестувати і з підтерапіями)

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

Якщо ви плутаєте:

Truthy: Це врешті-решт досягне двох, без проміжного кроку, що має будь-які елементи, крім 1і 2. -Einkorn Enchanter 20 hours ago

Falsy: Кінцеве значення немає [2]. Проміжні терміни містять щось інше, ніж щось набір [1,2]. Ще пару речей, дивіться приклади.


Це , переможець буде найнижчим.


7
Чи можемо ми використовувати будь-яке значення фальси, а не просто -1?
mbomb007

1
Що ви маєте на увазі під "НЕ робочим приставкою послідовності Колакоського"? Я припускав, що ти маєш на увазі, що список не може досягти, [2]поки я не побачив [2,2,1,1,2,1,2]тестовий випадок.
ngenisis

1
@ngenisis Це врешті-решт досягне двох, без проміжного кроку, що має будь-які елементи, крім 1і 2.
Пшеничний майстер

2
Може бути гарною ідеєю додати [1]як тестовий випадок.
Емінья

1
@ mbomb007 будь-яке чітке значення добре. Позитивне ціле число не годиться. Якщо ви 1-індексує 0, це добре. "Неправда" - це добре. Помилка - це добре. Будь-яке непозитивне значення повернення добре, навіть -129,42910.
Чарівний восьминіг Урна

Відповіді:


8

Haskell , 126 87 79 76 75 байт

39 байт збережено завдяки Шріану Йохансену

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

Спробуйте в Інтернеті!

Це помилки при неправильному введенні.


f(і, отже, !) можна значно скоротити, використовуючи ліниве виробництво + span/ lengthзамість акумуляторів. Спробуйте в Інтернеті!
Ørjan Johansen

1
Здається, щоб увійти до нескінченного циклу для[1]
Emigna

1
@Emigna Darn. Це коштує мені 6 байтів, щоб виправити це, але я це виправив.
Пшеничний майстер

@ ØrjanJohansen Це здається гарною підказкою, але я недостатньо досвідчений в Haskell, щоб зрозуміти, що там відбувається. Якщо ви хочете, ви можете опублікувати його як свою власну відповідь, але принаймні до тих пір, поки я не знаю, як працює ваше рішення, я не збираюся додавати його до своєї відповіді. :)
Пшеничний майстер

1
Я тоді зрозумів , що це той випадок , коли імпорт фактично коротше (і простіше зрозуміти): import Data.List;f l=length<$>group l. ( <$>є синонімом для mapцього.) Крім того, замість того, щоб мати два різних -1випадки, коротше використовувати @(_:_:_)шаблон, щоб змусити основний регістр лише відповідати довжині> = 2 списки. Спробуйте в Інтернеті!
Ørjan Johansen

6

05AB1E , 22 байти

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

Спробуйте в Інтернеті!

Пояснення

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

Не вдалося[1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,2,1,1]
Вейджун Чжоу

@WeijunZhou: Дякую, виправлено!
Емінья

Можливо, ви забули оновити посилання ...
Weijun Zhou

1
@WeijunZhou: Дійсно, мав. Ще раз дякую :)
Emigna

3

SCALA, 290 (282?) Знаків, 290 (282?) Байт

Мені знадобилося sooo loong ... Але я нарешті закінчила!

з цим кодом:

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

Я не знаю, чи варто мені рахувати var u=tбайти, враховуючи, що я не використовую tпід час роботи алгоритму (копія полягає лише в тому, щоб отримати змінний varзамість параметра, який tвважається val- спасибі ScaLa ). Скажіть, будь ласка, чи варто це рахувати.

Досить важко. Спробуйте в Інтернеті!

PS: Я думав зробити це рекурсивно, але мені доведеться передати лічильник як параметр справжньої рекурсивної "підфункції"; цей факт змушує мене оголосити дві функції, і ці символи / байти є не що інше, як втрачені.

EDIT: Мені довелося змінити (?), Оскільки ми не впевнені, що нам слід брати підрахунок [1]. Отже, ось модифікований код:

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

Це не оптимізовано (у мене є дублікат "out" для тих самих умов: коли я потрапляю [2]і коли до парам-класу [2]ставляться окремо).

НОВА ВАРТІСТЬ = 342 (я не змінив заголовок спеціально)


1
Здається, щоб увійти до нескінченного циклу для[1]
Емінья

Так, але, як сказано в ОП (як я принаймні зрозумів): "з початковим 1 видалено" та "Виведіть кількість повторень, перш ніж послідовність стане [2]"
В. Куртуа

Наскільки я розумію, [1]ніколи не досягає [2]і, таким чином, повертається -1 .
Емінья

Розумію. Отже, ти думаєш, я повинен поставити літтевий стан на початку? Дякую за вашу пораду.
В. Куртуа

Я не знаю scala, але я припускаю, що ви можете просто змінити цикл, щоб зупинитись, коли довжина списку менша за 2. Ви вже, здається, перевіряєте, що елемент у кінці 2.
Емінька

2

JavaScript, 146 142 байти

Спочатку спробуйте в коді гольф, здається, що "повернення" в більшій функції є досить стомлюючим ...

Крім того, перевірка b = 1 і b = 2 займає кілька байт ...

Ось код:

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}

Пояснення

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

Дані тестування (використовуючи дані тестових даних)

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]

Редагувати 1: 146 -> 142: Скасувати моє редагування щодо зменшення байтів, оскільки це впливає на вихід; а деякі редагують останнє твердження


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}економить 5 байтів (для циклу, а не час; коми проти дужок; && vs якщо). Ви можете скористатися компілятором закриття Google ( closure-compiler.appspot.com ), щоб виконати ці оптимізації для вас
Окі


2

JavaScript (ES6), 127 126 95 80 байт

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-індексований. Кидає "ReferenceError: X is not defined"і "InternalError: too much recursion"при поганому введенні.

Тестові справи


1

Clojure, 110 байт

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

Основна loopз попередньою перевіркою на крайових корпусах. Повернення nilдля недійсних входів. Я не знав, (= [2] '(2))це true: о


1

Python 2, 146 байт (лише функція)

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)

Повертає 0 на помилковому введенні (нормально, оскільки він 1-індексований). Просто використовуйте його так:

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

1

Математика, 82 байти

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

Functionякий неодноразово замінює {2}невизначений символ T, список (одного або декількох) 1s і 2s з наступною ітерацією та будь-чим іншим, 0поки не буде досягнуто фіксованої точки, потім повертає FirstPositionсимвол Tу отриманому FixedPointListмінусі 1. Вихід - це {n}де n( 1-вкладене) число ітерацій, необхідних для досягнення {2}правдоподібного випадку та фальшивого -1+Missing["NotFound"]випадку.

Якщо вихід повинен бути, nа не {n}, це коштує ще три байти:

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

1

Пітон 2 , 184 163 156 байт

  • @Felipe Нарді Батіста врятував 21 байт !!!! дуже дякую!!!!
  • Халвард Гуммель врятував 7 байт !! Спасибі

Python 2 , 156 байт

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

Спробуйте в Інтернеті!

Пояснення:

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 байти

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)

Спробуйте в Інтернеті!

Python 3 , 120 байт

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)

Спробуйте в Інтернеті!

Пояснення

Нова послідовність (w) ініціалізується для збереження наступної ітерації скорочення. Лічильник (c) використовується для відстеження кількості ітерацій.

Кожен елемент у вихідних послідовностях порівнюється з попереднім значенням. Якщо вони однакові, значення останнього елемента (w) збільшується на 1. Якщо вони різні, послідовність (w) розширюється на [1].

Якщо w == [2], лічильник (c) повертається. В іншому випадку, якщо вихідні послідовності (и) містять інші елементи, ніж 1 і 2, повертається значення -1. Якщо це не так, функція викликається рекурсивно з новою послідовністю (w) як (s), а лічильник (c) збільшується на 1.


Щоб зберегти байт, я намагаюся поєднати перші два рядки в def f(s,c=2,j=0,w=[1]):, але це дає інший результат. Хтось може пояснити, чому це так?
Джитсе


@JoKing Це має ідеальний сенс, дякую!
Джитце

0

R, 122 байти

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

Проходить усі тестові справи. Інакше викидає одну або кілька помилок. Я ненавиджу перевірки дійсності; цей код міг би бути настільки гольф, якби входи були приємними; це було б коротше, навіть якщо вхідні дані були послідовностями 1-х та 2-х, не обов'язково префіксом послідовності Колакоскі. Тут ми повинні перевірити як початковий вектор (інакше тестовий випадок [-2,1]) пройшов би), так і отриманий вектор (інакше [1,1,1]пройшов би).


0

Рубі , 81 77 байт

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}

Спробуйте в Інтернеті!

Редагувати: збережено 4 байти шляхом перетворення на рекурсивну лямбда.

Повертає 1-індексовану кількість ітерацій або 0 як фальси.

Використовує метод Ruby enumerable's chunk, який робить саме те, що нам потрібно - групуючи разом послідовні прогони однакових чисел. Довжини прогонів складають масив для наступної ітерації. Тримає ітерацію, поки масив довший 1 елемента і жодних номерів, окрім 1 та 2, не зустрічалося.


0

Pyth , 45 байт

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

Спробуйте в Інтернеті!

Це, мабуть, все ще пограбує. Це, безумовно, пограбовано, якби .?працювали так, як я сподівався, що це буде (будучи elseдля внутрішньої структури замість самої зовнішньої)

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.