Dada una lista de 1
s y -1
s, determinar si es o no es un válido código OVSF (mediante la salida de un Truthy o el valor Falsey-).
Los códigos OVSF se definen de la siguiente manera:
[1]
es un código OVSFSi
X
es un código OVSF, entoncesX ++ X
yX ++ -X
ambos son códigos OVSF.Aquí
++
está la concatenación de listas y-
niega todos los elementos de la lista.Ninguna otra lista son códigos OVSF válidos.
Puede suponer que la lista de entrada contiene solo -1
y 1
, pero debe manejar la lista vacía correctamente, así como las listas cuya longitud no es una potencia de 2.
El código más corto (en bytes) gana.
Casos de prueba
[] -> 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
Respuestas:
Jalea ,
18161411 bytesSalidas
[1]
(verdadero) para códigos OVSF,[]
(falso) de lo contrario.Pruébalo en línea!
Fondo
Al igual que @ respuesta MAT de LuisMendo y @ de XNOR respuesta Python , esta presentación verifica la matriz de entrada "del cabo dentro".
Cada par (no superpuesto) de elementos de un código OVSF de longitud dos o superior es esencialmente una copia del primer par, ya sea con los mismos signos o con ambos signos intercambiados. Del mismo modo, cada 4 tuplas (no superpuestas) de elementos de un código OVSF de longitud cuatro o superior es esencialmente una copia de las primeras 4 tuplas, ya sea con los mismos signos o con ambos signos intercambiados. Lo mismo es cierto para 8 tuplas, 16 tuplas, etc., hasta la longitud del código OVFS.
Una forma de verificar esto es verificar primero todos los pares para el módulo de igualdad del signo, luego eliminar el segundo elemento de cada par (que ahora es información redundante). Si repetimos este proceso una vez más, esencialmente estamos verificando las 4 tuplas. En la próxima iteración, estamos comparando 8-tuplas, etc.
Finalmente, si todas las 2 k- tuplas requeridas fueran iguales módulo el signo y la matriz se ha reducido a un singleton, es suficiente verificar si el elemento restante es un 1 .
Cómo funciona
fuente
Mathematica,
524745 bytesEl recuento de bytes supone la codificación CP-1252 y se
$CharacterEncoding
establece enWindowsANSI
(el valor predeterminado en las instalaciones de Windows).Esto define una función variadic
PlusMinus
, que toma la lista de entrada como una lista plana de argumentos y devuelve un valor booleano, por ejemplo,PlusMinus[1, -1, -1, 1]
daTrue
. Es teóricamente también puede utilizarse como un operador±
, pero que el operador sólo es válido sintácticamente en contextos unarios y binarios, por lo que la convención de llamada obtendría raro:±##&[1,-1,-1,1]
. Lanzará un montón de advertencias que pueden ignorarse.Esto también arrojará algunas advertencias que pueden ignorarse.
No podría estar lejos de acortar el algo molesto
a!==b!||{a}==-{b}
parte, pero no estoy encontrando nada en este momento. Palabras clave comoSubsetQ
yMatrixRank
son simplemente demasiado largas. : /Explicación
La solución básicamente difiere todas las cosas difíciles para el patrón de Mathematica y, por lo tanto, tiene un estilo muy declarativo. Además de cierta golfitud en la primera línea, esto realmente agrega tres definiciones diferentes para el operador
±
:Las dos primeras filas se acortaron anidando las definiciones y expresando
True
como1>0
.Deberíamos deconstruir esto aún más para mostrar cómo esto realmente define una función variadci
PlusMinus
usando solo la notación de operador unario y binario. El problema es que todos los operadores son simplemente azúcar sintáctica para expresiones completas. En nuestro caso±
corresponde aPlusMinus
. El siguiente código es 100% equivalente:Mediante el uso de secuencias (más o menos como símbolos en otros idiomas) como operandos
±
, podemos cubrir una cantidad arbitraria de argumentos paraPlusMinus
, aunque±
no sea utilizable con más de dos argumentos. La razón fundamental es que el azúcar sintáctico se resuelve primero, antes de que cualquiera de estas secuencias se expanda.A las definiciones:
La primera definición es simplemente una alternativa (
___
coincide con una lista arbitraria de argumentos). Cualquier cosa que no coincida con las definiciones más específicas a continuación daráFalse
.La segunda definición es el caso base para el OVSF, la lista contiene solo
1
. Definimos esto para serTrue
.Finalmente, la tercera definición se aplica solo a las listas que se pueden descomponer en
X ++ X
oX ++ -X
, y utiliza recursivamente el resultado paraX
. La definición se limita a estas listas asegurándose de que se puede dividir en subsecuenciasa
yb
cona__±b__
y luego unir la condición (/;
) que, o bien{a}=={b}
o{a}==-{b}
. La definiciónPlusMinus
como una función variada de esta forma extraña a través de un operador ahorra la friolera de 5 bytes sobre la definición de un operador unario±
en las listas.Pero espera hay mas. Estamos usando en
a!==b!
lugar de{a}=={b}
. Claramente, estamos haciendo esto porque es dos bytes más corto, pero la pregunta interesante es por qué funciona. Como he explicado anteriormente, todos los operadores son solo azúcar sintáctico para alguna expresión con cabeza.{a}
esList[a]
. Peroa
es una secuencia (como dije, algo así como un splat en otros idiomas) así que sia
es1,-1,1
así, obtenemosList[1,-1,1]
. Ahora postfix!
esFactorial
. Así que aquí, llegaríamosFactorial[1,-1,1]
. PeroFactorial
no sabe qué hacer cuando tiene un número diferente de argumentos que uno, por lo que esto simplemente permanece sin evaluar.==
realmente no le importa si las cosas en ambos lados son listas, solo compara las expresiones, y si son iguales daTrue
(en este caso, no dará realmenteFalse
si no lo son, pero los patrones no coinciden si la condición devuelve algo más queTrue
). Eso significa que la verificación de igualdad aún funciona si hay al menos dos elementos en las listas. ¿Qué pasa si solo hay uno? Sia
es,1
entoncesa!
está quieto1
. Sia
es-1
entoncesa!
daComplexInfinity
. Ahora, compararse1
a sí mismo todavía funciona bien, por supuesto. PeroComplexInfinity == ComplexInfinity
permanece sin evaluar, y no da verdad a pesar de todoa == -1 == b
. Afortunadamente, esto no importa, porque la única situación en la que esto aparece esPlusMinus[-1, -1]
que no es un OVSF válido de todos modos. (Si la condición volvieraTrue
, la llamada recursiva informaríaFalse
después de todo, así que no importa que el cheque no funcione). No podemos usar el mismo truco{a}==-{b}
porque-
noFactorial
se enhebra, solo se enhebraList
.El emparejador de patrones se encargará del resto y simplemente encontrará la definición correcta para aplicar.
fuente
Haskell, 57 bytes
Dada la lista de entrada
l
, crece un código OVSFs
comenzando desde[1]
y concatenando repetidamente cualquieras
o-s
, lo que haga que el primer elemento coincida con el del
. Luego, verifica que el resultado estél
al final. Esto se verifica una vez ques
tiene una longitud de al menos la del
.Algunas estructuras recursivas alternativas también dieron 57:
fuente
MATLAB / Octave , 94 bytes
Esto está utilizando un nuevo enfoque: los códigos de longitud OVSF permitidos
N
aparecen en lalog2(N)
-math Walsh-matrix , ya que están básicamente definidos por la misma recursividad:Las matrices de Walsh son casos especiales de las matrices de tamaño Hadamard
N x N
siN
es una potencia de dos. (También hay matrices Hadamard de otros tamaños). MATLAB y Octave tienen una variedad de funciones integradas que generan matrices de prueba para probar las propiedades de algoritmos numéricos, entre ellashadamard()
. Afortunadamente para los poderes de dos MATLAB,hadamard()
usex exactamente la construcción de las matrices galesas.Entonces, esta función primero verifica si la longitud de las entradas es una potencia de dos, y si lo es, verifica si es una fila del tamaño correspondiente de la matriz de Gales.
Pruébalo en línea!
fuente
Python, 64 bytes
Divide la lista en elementos indexados pares y elementos indexados impares a través de sectores. Comprueba si los vectores de resultado son iguales o negativos multiplicando uno por el signo forzado por su primer elemento. Luego, realiza la misma verificación recursiva en los elementos indexados pares.
Para el caso base, si la verificación falla, se rechaza a menos que la lista lo sea
[1]
. La lista vacía también se rechaza específicamente para evitar un bucle infinito.Una estrategia diferente como mi respuesta de Haskell da 66 bytes:
fuente
Haskell ,
106 91 8786 bytesLa función
g
genera lan
iteración de listas (relativamente ineficiente, ya quelength $ g n == 3^n
, sin embargo, si eliminamos los duplicados, obtendríamos2^n
),f
verifica si nuestra lista está en alguno de ellos. ¡Gracias a @Zgrab por algunas pistas!Pruébalo en línea!
fuente
g
es muy ineficiente y produce una tonelada de duplicados. (Verifique la sección de depuración , probablemente se deba a limitaciones de tiempo o memoria.)JavaScript (ES6),
13093878583 bytesManifestación
fuente
JavaScript (ES6),
8561 bytesVersión anterior que verificó elementos para asegurarse de que eran
1
o-1
:Explicación:
a[22] == a[2] * a[4] * a[16]
. Comoa[20] == a[4] * a[16]
ya se ha verificado, soloa[22] == a[2] * a[20]
es necesario verificarlo.i
no tener al menos dos bits establecidos. En el caso del conjunto de bits cero, verifica esoa[0] == a[0] * a[0]
, lo cual es falsoa[0] == -1
, mientras que en el caso de un conjunto de bits, lo verificaa[i] == a[0] * a[i]
.fuente
(l=a.length)&&!(l&l-1)
para(l=a.length)&-l==l
guardar 4 bytesl==0
?(l=a.length)&&l&-l==l
? guardar 1 byte ...[1,1,1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,1]
incluso sin mis sugerencias.l&-l==l
no funciona porque==
tiene mayor prioridad que&
. Y el caso de prueba no funciona debido a un error tipográfico que me costará un byte solucionar.MATL ,
2120 bytesPruébalo en línea! O verificar todos los casos de prueba .
Cómo funciona
El código divide la matriz en dos partes de igual longitud: la primera con las entradas indexadas impares, la segunda con las entradas indexadas pares. Las dos piezas están obligadas a tener la misma longitud, con un relleno cero en el segundo si es necesario. Entonces el código verifica que
Si se cumplen estas tres condiciones, el proceso se aplica nuevamente en la primera pieza. Si se sale del bucle porque la longitud ya era 1, la entrada es un código OFSV. De lo contrario no lo es.
La condición 1 iterada es una versión equivalente de la propiedad definitoria de los códigos OVSF. Para una matriz de, digamos, longitud 8, el enfoque directo sería verificar que las entradas 1, 2, 3, 4 sean todas iguales o diferentes a las entradas 5, 6, 7, 8 respectivamente (esta es la propiedad que define). Pero podemos comprobar de manera equivalente que las entradas 1,3,5,7 son todas iguales o diferentes a las entradas 2,4,6,8 respectivamente; y esto resulta usar menos bytes.
La condición 2 asegura que la longitud de entrada sea una potencia de 2: si no es así, se introducirá un relleno cero en algún momento.
fuente
Haskell, 66 bytes
¡Yay, listas infinitas!
Versiones alternativas:
fuente
(0-)
truco, estaba atrapado connegate
o((-1)*)
APL, 46 bytes
Bastante sencillo:
0::0
: si se produce un error, devuelve 0⍵≡,1:1
: si la entrada es exactamente[1]
, devuelve 1⍬≡⍵:0
: si la entrada es la lista vacía, devuelve 0Z←.5×⍴⍵
:Z
es la mitad de la longitud de la entradaY←⍵↓⍨Z
:Y
es la última mitad de la entrada (esto falla si⍴⍵
es desigual, activando el controlador de excepciones)(∇Y)∨∇-Y
: la última mitad de la lista, o la negación de la última mitad de la lista, debe ser un código OVSF(∇Z↑⍵)∧
: y la primera mitad de la lista debe ser un código OVSF.fuente
Haskell,
6968 bytesEjemplo de uso:
g [-1,1]
->False
.Aún más ineficiente que la respuesta de @ flawr . Se necesita demasiado tiempo y memoria para las listas de 4 elementos. Para ver que realmente se crea la lista de códigos OVSF (con muchos duplicados), intente:
que vuelve
es decir, la lista comienza con las 16 listas de elementos (4 veces concatenadas, debido a
[1..4]
), continúa con las 8 listas de elementos y así sucesivamente hasta que termina con[1]
.Editar: @xnor guardó un byte. ¡Gracias!
fuente
scanr
!any(elem x)
lugar deelem x$c
y no definiendoc
.Python 2 ,
7875 bytesPruébalo en línea!
fuente
JavaScript (ES6), 80
Construye recursivamente y verifica cada lista hasta la longitud de la lista de entrada, comenzando con
[1]
.El valor de retorno es JS Truthy o Falsey-, en concreto
1
, otrue
si es válido,0
ofalse
, oundefined
si no es válido.Prueba
fuente
Clojure, 118 bytes
Divide la entrada
c
en dos mitadesa
yb
comprueba si sus productos con elementos son todos idénticos. Si es así, verifica que la primera mitad sea una secuencia válida.Este es de 142 bytes pero lo encontré más interesante:
loop
calculalog_2
la longitud de la entrada,iterate
genera secuencias de tantas iteraciones basadas en la definición. Esto devuelve el argumento de entrada si es una secuencia válida y de lonil
contrario.fuente