Сокращение Колакоски


27

обзор

Некоторым из вас может быть известна последовательность Колакоски ( A000002 ), хорошо известная самоссылочная последовательность, которая имеет следующее свойство:

Coolio Колакоски собственности, йо.

Это последовательность, содержащая только 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

Если вы запутались:

Правда: в конечном итоге он достигнет двух без какого-либо промежуточного шага, имеющего какие-либо элементы, кроме 1и 2. -Einkorn Enchanter 20 hours ago

Ложь: конечное значение нет [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вместо аккумуляторов. Попробуйте онлайн!
Орджан Йохансен

1
Кажется, чтобы войти в бесконечный цикл для[1]
Emigna

1
@ Emigna Darn. Это стоит мне 6 байт, чтобы исправить это, но я исправил это.
Пшеничный волшебник

@ ØrjanJohansen Это хороший совет, но я не достаточно опытен в Хаскеле, чтобы понять, что там происходит. Если вы хотите, вы можете опубликовать его как собственный ответ, но, по крайней мере, пока я не знаю, как работает ваше решение, я не собираюсь добавлять его в свой ответ. :)
Wheat Wizard

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

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: действительно, я имел.
Еще

3

SCALA, 290 (282?) Символов, 290 (282?) Байтов

Это заняло у меня тааак лун ... Но я наконец-то сделал!

с этим кодом:

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: я думал сделать это рекурсивно, но мне придется передать счетчик в качестве параметра истинной рекурсивной «подфункции»; этот факт заставляет меня объявить две функции, и эти символы / байты просто потеряны.

РЕДАКТИРОВАТЬ: Я должен был изменить (?), Потому что мы не уверены, что мы должны принять в [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]обрабатывается отдельно).

NEW COST = 342 (я не изменил название специально)


1
Кажется, чтобы ввести бесконечный цикл для[1]
Emigna

Да, но как сказал OP (как я понял по крайней мере): «с удаленным начальным 1» и «Выведите количество итераций до того, как последовательность станет [2]»
V. Courtois

Насколько я понимаю, [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 байт (для цикла вместо while; запятые против фигурных скобок; && vs if). Вы можете использовать закрывающий компилятор Google ( closure-compiler.appspot.com ), чтобы сделать эти оптимизации для вас
Oki

2

Желе ,26 25 22 21 20 байт

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

Попробуйте онлайн!

Этот код фактически не работал правильно до 20 байт, и я даже не заметил; это не удалось в [2,2]тестовом случае. Должно работать отлично сейчас.


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: o


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

Mathematica, 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-indexed) число итераций , необходимых для достижения {2}для случая truthy и -1+Missing["NotFound"]для falsy случая.

Если выходные данные должны быть, nа не {n}, это стоит еще три байта:

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

1

Python 2 , 184 163 156 байт

  • @ Филипе Нарди Батиста сэкономил 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, который делает именно то, что нам нужно - группировать последовательные серии одинаковых чисел. Длины прогонов составляют массив для следующей итерации. Продолжает итерацию, пока массив длиннее 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.