Это код OVSF?


27

Учитывая список 1s и -1s, определите, является ли это действительным кодом OVSF (выводя значение true или false).

Коды OVSF определяются следующим образом:

  • [1] это код OVSF

  • Если Xэто код OVSF, то X ++ Xи X ++ -Xоба являются кодами OVSF.

    Вот ++конкатенация списка, и -отрицает каждый элемент в списке.

  • Никакие другие списки не являются действительными кодами OVSF.

Вы можете предположить, что входной список содержит только -1и 1, но вы должны правильно обрабатывать пустой список, а также списки, длина которых не равна степени 2.

Самый короткий код (в байтах) выигрывает.

Контрольные примеры

[] -> False
[1] -> True
[-1] -> False
[1, 1] -> True
[1, -1] -> True
[1, 1, 1, 1] -> True
[1, 1, 1, 1, 1] -> False
[1, -1, -1, 1, -1, 1, 1, -1] -> True
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1] -> True

5
Что означает "OVSF"?
NoOneIsHere

5
Коэффициент расширения ортогональной переменной , который относится к способу их использования, а также к их полезному свойству. Это не очень уместно, но ссылка на Википедию объясняет все это (смутно).
Линн

Ответы:


8

Желе , 18 16 14 11 байт

^2/Eam2µḊ¿Ṭ

Выводы [1](правда) для кодов OVSF, [](ложно) в противном случае.

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

Задний план

Как @ MATL ответ LuisMendo в и @ XNOR Ответим Python , это представление проверяет входной массив «от наизнанку».

Каждая (не перекрывающаяся) пара элементов кода OVSF длиной два или выше по сути является копией первой пары, либо с одинаковыми знаками, либо с заменой обоих знаков. Аналогично, каждый (не перекрывающийся) 4-й кортеж элементов кода OVSF длиной четыре или выше по сути является копией первого 4-кортежа, либо с одинаковыми знаками, либо с заменой обоих знаков. То же самое относится к 8-кортежам, 16-кортежам и т. Д., Вплоть до длины кода OVFS.

Один из способов проверить это - сначала проверить все пары на равенство по знаку, а затем удалить второй элемент каждой пары (который теперь является избыточной информацией). Если мы повторим этот процесс еще раз, мы по существу проверяем все 4 кортежа. В следующей итерации мы сравниваем 8 кортежей и т. Д.

Наконец, если все необходимые 2 k- кортежи были равны по модулю знака и массив был уменьшен до одиночного, достаточно проверить, равен ли оставшийся элемент 1 .

Как это работает

^2/Eam2µḊ¿Ṭ  Main link. Argument: A (array of 1's and -1's)

       µḊ¿   While dequeuing A (removing its first element) yields a non-empty
             array, execute the monadic chain to the left, updating A with the
             return value after each iteration.
^2/            Compute the bitwise XOR of each non-overlapping pair of elements of
               A. Note that 1 ^ 1 = 0 = -1 ^ -1 and 1 ^ -1 = -2 = -1 ^ 1.
               For an array of even length that consists of the same pairs modulo
               the sign, this returns either an array of 0's or an array of -2's.
               If the length is odd, it will also contain the last element, which
               is either a 1 or a -1.
   E           Test the elements of the result for equality. This yields 1 if the
               array consists solely of 0's or solely of -2's, 0 otherwise.
    a          Take the logical AND of the previous result and every element of A.
               This returns A if it passed the previous test, but replaces all of
               its elements with 0's otherwise.
     m2        Modulo 2; select every second element of A, starting with the first.
             At this point, the last return value can be:
               • [  ] if the input was empty
               • [ 1] if the input was a valid OVSF code
               • [-1] if the input was the negative of a valid OVSF code.
               • [ 0] in all other cases.
           Ṭ  Untruth; yield an array with 1's at the specified indices.
              Indexing is 1-based in Jelly, so [1] returns [1], the array with a 1
              at index 1. Since the indices -1 and 0 are non-canonical, the arrays
              [-1] and [0] are mapped to []. The empty array remains empty.

14

Mathematica, 52 47 45 байт

Число байтов предполагает кодировку CP-1252 и $CharacterEncodingустановлено в значение WindowsANSI(по умолчанию в установках Windows).

±___=!(±1=1>0)
a__±b__/;a!==b!||{a}==-{b}:=±a

Это определяет переменную функцию PlusMinus, которая принимает входной список как плоский список аргументов и возвращает логическое значение, например, PlusMinus[1, -1, -1, 1]дает True. Это теоретически также можно использовать в качестве оператора ±, но оператор только синтаксически действует в одинарных и двойных контекстах, поэтому соглашение о вызовах бы получить странно: ±##&[1,-1,-1,1]. Он выдаст кучу предупреждений, которые можно игнорировать.

Это также выдаст несколько предупреждений, которые можно игнорировать.

Там может быть что-то, чтобы сократить несколько раздражающую a!==b!||{a}==-{b}часть, но я сейчас ничего не нахожу. Ключевые слова, как SubsetQи MatrixRankпросто слишком долго. : /

объяснение

Решение в основном переносит все хитрости на Mathematica, и поэтому оно очень декларативно по стилю. Помимо некоторого гольф-поля на первой линии, это действительно просто добавляет три разных определения для оператора ±:

±___=False;
±1=True;
a__±b__/;a!==b!||{a}==-{b}:=±a

Первые две строки были сокращены путем вложения определений и выражения Trueкак 1>0.

Мы должны деконструировать это далее, чтобы показать, как это на самом деле определяет функцию variadci PlusMinus, используя только унарные и двоичные операторные обозначения. Загвоздка в том, что все операторы являются просто синтаксическим сахаром для полных выражений. В нашем случае ±соответствует PlusMinus. Следующий код на 100% эквивалентен:

PlusMinus[___]=False;
PlusMinus[1]=True;
PlusMinus[a__,b__]/;a!==b!||{a}==-{b}:=PlusMinus[a]

Используя в качестве операндов последовательности (вроде сплатов в других языках), ±мы можем охватить произвольное количество аргументов PlusMinus, даже если их ±нельзя использовать более чем с двумя аргументами. Основная причина заключается в том, что синтаксический сахар разрешается в первую очередь, прежде чем любая из этих последовательностей будет расширена.

По определениям:

Первое определение - просто запасной вариант ( ___соответствует произвольному списку аргументов). Все, что не соответствует более конкретным определениям ниже, даст False.

Второе определение - базовый вариант для OVSF, список содержит только 1. Мы определяем это как True.

Наконец, третье определение применяется только к спискам, которые можно разложить на X ++ Xили X ++ -X, и рекурсивно использует результат для X. Определение ограничивается этими списками, обеспечивая их можно разделить на подпоследовательности aи bс a__±b__и затем присоединив условие ( /;) , что либо {a}=={b}или {a}==-{b}. Определяя PlusMinusэту функцию как переменную таким странным способом с помощью оператора, вы сэкономите 5 байтов за определение унарного оператора ±в списках.

Но подождите, это еще не все. Мы используем a!==b!вместо {a}=={b}. Ясно, что мы делаем это, потому что это на два байта короче, но интересный вопрос, почему это работает. Как я объяснил выше, все операторы являются просто синтаксическим сахаром для некоторого выражения с головой. {a}есть List[a]. Но aэто последовательность (как я уже сказал, что-то вроде восклицательного знака в других языках), так что если aэто так, 1,-1,1мы получаем List[1,-1,1]. Теперь постфикс !есть Factorial. Итак, мы получили Factorial[1,-1,1]. Но Factorialон не знает, что делать, когда у него количество аргументов, отличное от одного, поэтому это просто остается недооцененным. ==на самом деле не волнует, являются ли вещи с обеих сторон списками, просто сравниваются выражения, и если они равны, это даетTrue(в этом случае, на самом деле это не даст, Falseесли это не так, но шаблоны не совпадают, если условие возвращает что-либо кроме True). Таким образом, проверка на равенство по-прежнему работает, если в списках есть хотя бы два элемента. Что если есть только один? Если aесть, 1то a!еще 1. Если aесть, -1то a!дает ComplexInfinity. Теперь, по сравнению 1с самим собой, все еще работает нормально, конечно. Но ComplexInfinity == ComplexInfinityостается неоцененным и не дает правды, хотя a == -1 == b. К счастью, это не имеет значения, потому что единственная ситуация, в которой это проявляется, это то, PlusMinus[-1, -1]что в любом случае не является действительным OVSF! (Если условие вернулось True, рекурсивный вызов сообщитFalseв конце концов, так что это не имеет значения , что проверка не работает.) Мы не можем использовать тот же трюк для , {a}==-{b}потому что -не будет нить через Factorialэто только нити более List.

Сопоставитель шаблонов позаботится обо всем остальном и просто найдет правильное определение для применения.


9

Haskell, 57 байт

q=length
f l=l==until((>=q l).q)(\s->s++map(*l!!q s)s)[1]

С учетом ввода списка l, растет код OVSF s, начиная с [1]и повторно конкатенации либо sили -s, в зависимости от того делает первый элемент совпадающее l. Затем проверяет, что результат lв конце. Это проверено, как только sимеет длину, по крайней мере, длины l.

Некоторые альтернативы рекурсивным структурам также дают 57:

(s%i)l|length l<=i=s==l|j<-2*i=(s++map(*l!!i)s)%j$l
[1]%1

q=length
s%l|q s>=q l=s==l|r<-s++map(*l!!q s)s=r%l
([1]%)

q=length
g s l|q s<q l=g(s++map(*l!!q s)s)l|1>0=s==l
g[1]

6

MATLAB / Octave , 94 байта

function a=f(r);n=nnz(r);m=log2(n);a=0;if fix(m)-m==0;for c=hadamard(n);a=a+all(r==c');end;end

При этом используется новый подход: разрешенные коды длины OVSF Nпоявляются в log2(N)-ой матрице Уолша , так как они в основном определяются одной и той же рекурсией:

Матрицы Уолша являются частными случаями матриц Адамара размера, N x Nесли Nявляется степенью двойки. (Существуют также матрицы Адамара других размеров.) MATLAB и Octave имеют множество встроенных функций, которые генерируют тестовые матрицы для проверки свойств численных алгоритмов, среди которых есть hadamard(). К счастью для степеней использования двух MATLAB hadamard()точно построение валлийских матриц.

Таким образом, эта функция сначала проверяет, является ли длина входов степенью двойки, и, если она есть, она проверяет, является ли она строкой валлийской матрицы соответствующего размера.

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


5

Python, 64 байта

f=lambda l:[]<l[1::2]==[x*l[1]for x in l[::2]]*f(l[::2])or[1]==l

Разбивает список на четные и нечетные элементы с помощью срезов. Проверяет, являются ли векторы результата равными или отрицательными, умножая один на знак, навязанный его первым элементом. Затем выполняет ту же рекурсивную проверку для элементов с четным индексом.

Для базового случая, если проверка не пройдена, отклоняется, если список не установлен [1]. Пустой список также специально отклоняется, чтобы избежать бесконечного цикла.

Другая стратегия, такая как мой ответ на Haskell, дает 66 байтов:

f=lambda l,i=1,s=[1]:l[i:]and f(l,i*2,s+[x*l[i]for x in s])or s==l

2

Haskell , 106 91 87 86 байт

g n|n<1=[[1]]|m<-g(n-1)=foldl(\a b->[b++map(0-)b,b++b]++a)[]m++m
f l=elem l$g$length l

Функция gгенерирует nитерацию списков (относительно неэффективно, поскольку length $ g n == 3^n, однако, если мы удалим дубликаты, мы получим 2^n), fпроверяет, есть ли наш список в каком-либо из них. Спасибо @Zgrab за несколько советов!

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


Выполнение последних 2 тестовых случаев не дало результата для меня.
Оливер

@obarakon Да, это потому , что gэто очень неэффективно и производит тонну дублей. (Проверьте раздел отладки , это, вероятно, связано с ограничениями по времени или памяти.)
flawr

2

JavaScript (ES6), 130 93 87 85 83 байта

f=a=>(b=a.slice(0,l=a.length/2),c=a.slice(l)+"",a==1||l&&b==c|b.map(i=>-i)==c&f(b))

демонстрация

f=a=>(b=a.slice(0,l=a.length/2),c=a.slice(l)+"",a==1||l&&b==c|b.map(i=>-i)==c&f(b)),[[],[1],[-1],[1,1],[1,-1],[1,1,1,1],[1,1,1,1,1],[1,-1,-1,1,-1,1,1,-1],[1,1,1,1,-1,-1,-1,-1,1,1,1,1],[1,1,1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1],[1,1,1,1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1]].map(a=>console.log(`[${a}] -> ${!!f(a)}`))


2

JavaScript (ES6), 85 61 байт

a=>(l=a.length)&&!(l&l-1)&a.every((e,i)=>e==a[j=i&-i]*a[i-j])

Предыдущая версия, которая проверяла элементы, чтобы убедиться, что они были 1или -1:

a=>(l=a.length)&&!(l&l-1)&a.every((e,i)=>i?(j=i&-i)<i?e==a[j]*a[i-j]:e==1|e==-1:e==1)

Объяснение:

  • Длина не может быть нулевой
  • Длина должна быть степенью 2
  • Первый элемент должен быть 1
  • Элементы в позициях, которые имеют степень 2, должны быть либо 1, либо -1
  • Элементы в других позициях являются произведением всех элементов в позициях, соответствующих битовой маске, например a[22] == a[2] * a[4] * a[16]. Так a[20] == a[4] * a[16]как уже проверено, a[22] == a[2] * a[20]нужно только проверить.
  • Приведенная выше проверка дает вырожденные результаты, если iне установлено хотя бы два бита. В случае установки нулевых битов он проверяет это a[0] == a[0] * a[0], что ложно для a[0] == -1, в то время как в случае установки одного бита это проверяет a[i] == a[0] * a[i].

Вы можете изменить, (l=a.length)&&!(l&l-1)чтобы (l=a.length)&-l==lсохранить 4 байта
Патрик Робертс

@PatrickRoberts Не правда l==0ли?
Нил

О, ты прав. Ну тогда (l=a.length)&&l&-l==l? сохранить 1 байт ...
Патрик Робертс

На самом деле не имеет значения, ваша функция не работает, [1,1,1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1]даже без моих предложений.
Патрик Робертс

@PatrickRoberts l&-l==lне работает, потому что ==имеет более высокий приоритет, чем &. И контрольный пример не работает из-за опечатки, которая будет стоить мне байта, чтобы исправить.
Нил

2

MATL , 21 20 байт

`2eZ}yy=&=tn1>hh]1X=

Попробуйте онлайн! Или проверьте все тестовые случаи .

Как это работает

Код разбивает массив на две части равной длины: первая с записями с нечетным индексом, вторая с записями с четным индексом. Две части должны иметь одинаковую длину, с добавочным нулем во второй при необходимости. Затем код проверяет, что

  1. Соответствующие записи двух частей либо все равны, либо все разные;
  2. Ни одна запись во второй части не равна нулю;
  3. Длина кусков превышает 1.

Если эти три условия соблюдены, процесс снова применяется к первому фрагменту. Если цикл завершен из-за того, что длина уже была равна 1, вводом является код OFSV. Иначе это не так.

Условие 1 повторное является эквивалентной версией определяющего свойства кодов OVSF. Для массива, скажем, длины 8, простой подход заключается в проверке того, что записи 1, 2, 3, 4 равны или все отличаются от записей 5, 6, 7, 8 соответственно (это определяющее свойство). Но мы можем эквивалентно проверить, что записи 1,3,5,7 все равны или отличаются от записей 2,4,6,8 соответственно; и это оказывается использовать меньше байтов.

Условие 2 гарантирует, что входная длина является степенью 2: если это не так, на некоторой стадии будет добавлен нулевой отступ.

`        % Do...while loop
  2e     %   Reshape as a two-row matrix, with a padding zero if needed
         %   Row 1 contains the original odd-indexed entries, row 2 the
         %   even-indexed
  Z}     %   Split matrix into two vectors, one corresponding to each row
  yy     %   Duplicate those two vectors
  =      %   Check if corresponding entries are equal or not
  &=     %   Matrix of all pairwise comparisons. This will give a matrix
         %   filled with ones if and only if the previous check gave all
         %   true or all false (condition 1)
  tn1>   %   Duplicate and push true if size exceeds 1, or false otherwise
         %   (condition 3)
  hh     %   Concatenate condition 1, condition 3, and the original copy of
         %   the second piece (condition 2). The resulting vector is truthy
         %   if and only if it doesn't contain any zero
]        % End
1X=      % True if top of the stack is a single 1, false otherwise

2

Haskell, 66 байт

Ууу, бесконечные списки!

o=[1]:(o>>= \x->[x++map(0-)x,x++x])
f l=l`elem`take(2*2^length l)o

Альтернативные версии:

o=[1]:(o<**>map(>>=flip(++))[map(0-),id])
f=Data.List.Ordered.hasBy(comparing length)o

Спасибо за (0-)трюк, я застрял с negateили((-1)*)
Берги

1

APL, 46 байт

{0::0⋄⍵≡,1:1⋄⍬≡⍵:0⋄(∇Z↑⍵)∧(∇Y)∨∇-Y←⍵↓⍨Z←.5×⍴⍵}

Довольно просто:

  • Базовые случаи:
    • 0::0: если произошла ошибка, верните 0
    • ⍵≡,1:1: если ввод точно [1], вернуть 1
    • ⍬≡⍵:0: если вход пустой список, вернуть 0
  • Рекурсивный случай:
    • Z←.5×⍴⍵: Zполовина длины ввода
    • Y←⍵↓⍨Z: Yявляется последней половиной входных данных (это не работает, если ⍴⍵неравномерно, вызывая обработчик исключений)
    • (∇Y)∨∇-Y: либо последняя половина списка, либо отрицание последней половины списка, должно быть кодом OVSF
    • (∇Z↑⍵)∧: и первая половина списка должна быть кодом OVSF.

1
Я не думаю, что достаточно проверить OVSF-кодирование для второй половины; оно должно быть равно первой половине или ее отрицанию.
Згарб

1
говорят, что бейсик - высокий уровень томности, а APL - высокий уровень страданий: ')
кот

говорят, что бейсик - высокий уровень томности, а APL - высокий уровень страданий: ')
кот

1

Haskell, 69 68 байт

g x=any(elem x)$scanr(\_->concat.mapM(\y->[y++y,y++map(0-)y]))[[1]]x

Пример использования: g [-1,1]-> False.

Даже более неэффективно, чем ответ @ flawr . Это занимает слишком много времени и памяти для списков из 4 элементов. Чтобы увидеть, что список кодов OVSF (с большим количеством дубликатов) действительно создан, попробуйте:

take 10 $ c $ scanr(\_->concat.mapM(\y->[y++y,y++map(0-)y]))[[1]] [1..4]

который возвращается

[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
 [1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
 [1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1],
 [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1],
 [1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1],
 [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1],
 [1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
 [1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1]]

т. е. список начинается со всех 16 списков элементов (из-за четырехкратной конкатенации [1..4]), продолжается со всеми 8 списками элементов и так далее, пока не заканчивается [1].

Редактировать: @xnor сохранил байт. Благодарность!


Ах, я совсем забыл о scanr!
flawr

Я думаю, что вы можете сократить байт, сделав any(elem x)вместо, elem x$cа не определяя c.
xnor


0

JavaScript (ES6), 80

f=(l,k=[1])=>l+l==k+k||l[k.length]&&f(l,k.concat(k))|f(l,k.concat(k.map(v=>-v)))

Рекурсивно строит и проверяет каждый список по длине списка ввода, начиная с [1].

Возвращаемое значение JS truthy или falsey, в частности , 1или trueесли действительно, 0или , falseили , undefinedесли не действует.

Тест

f=(l,k=[1])=>l+l==k+k||l[k.length]&&f(l,k.concat(k))|f(l,k.concat(k.map(v=>-v)))

test=`[] -> False
[1] -> True
[-1] -> False
[1, 1] -> True
[1, -1] -> True
[1, 1, 1, 1] -> True
[1, 1, 1, 1, 1] -> False
[1, -1, -1, 1, -1, 1, 1, -1] -> True
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1] -> False
[1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1] -> True`
.split('\n')

test.forEach(r=>{
  input = r.match(/-?1/g)||[]
  check = r.slice(-4) == 'True'
  result = f(input)
  console.log(result, check, '['+input+']')
})


0

Clojure, 118 байт

(defn f[C](or(=(count C)1)(let[l(/(count C)2)[a b](split-at l C)](and(> l 0)(=(count b)l)(apply =(map * a b))(f a)))))

Разбивает входные данные cна две половины aи bи проверяет, все ли их поэлементные произведения идентичны. Если это так, проверяет, что первая половина является допустимой последовательностью.

Это 142 байта, но я нашел его более интересным:

#((set(nth(iterate(fn[I](mapcat(fn[i][(concat i i)(concat i(map - i))])I))[[1][-1]])(loop[l(count %)i 0](if(< l 2)i(recur(/ l 2)(inc i))))))%)

loopвычисляет log_2длину ввода, iterateгенерирует последовательности из этого количества итераций на основе определения. Это возвращает входной аргумент, если это допустимая последовательность и в nilпротивном случае.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.