Un "esquema de rima" es una cadena de letras a
para z
, de modo que las primeras apariciones de los caracteres están en orden ascendente (sin espacios), comenzando desde a
. Por ejemplo (con las primeras ocurrencias marcadas):
abccdbebdcfa
^^^ ^ ^ ^
La cantidad de esquemas de rima de longitud N
viene dada por los números de Bell B(N)
. ( OEIS A000110 )
El reto
Su tarea es implementar una enumeración de estos esquemas de rima, es decir, un mapeo biyectivo de enteros a esquemas de rima. Te dan un número entero positivo N <= 26
, así como un número entero no negativo 0 <= i < B(N)
. Alternativamente, puede usar el rango 1 <= i <= B(N)
. Debe generar un esquema de rima de longitud N
, de modo que cada uno i
produzca una cadena diferente.
Puede escribir un programa o función, tomando la entrada a través de STDIN (o la alternativa más cercana), argumento de línea de comando o argumento de función y generando el resultado a través de STDOUT (o la alternativa más cercana), el valor de retorno de la función o el parámetro de función (out).
Puede usar letras minúsculas o mayúsculas (consistentemente).
Su código debe ser capaz de manejar cualquier entrada válida en un tiempo razonable (por ejemplo, no más de unas pocas horas para el N = 26
peor de los casos i
). Esto debería permitir soluciones que se escalen exponencialmente con N
(para bases pequeñas), incluso en lenguajes lentos pero que prohíban soluciones que se escalen linealmente con i
(es decir B(N)
). En particular, eso significa que no puede simplemente iterar a través de todos los esquemas de longitud de rima válidos N
hasta que haya descartado los i
esquemas.
Se aplican reglas estándar de código de golf .
Ejemplos
La asignación exacta de los i
esquemas to (es decir, el orden de los esquemas para un determinado N
) depende de usted. Pero supongamos que eligió el orden lexicográfico, su solución debe corresponder a la siguiente tabla (con una -
entrada no válida):
N\i 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 a - - - - - - - - - - - - - -
2 aa ab - - - - - - - - - - - - -
3 aaa aab aba abb abc - - - - - - - - - -
4 aaaa aaab aaba aabb aabc abaa abab abac abba abbb abbc abca abcb abcc abcd
Aquí hay un breve script de CJam que genera todos los esquemas de rima válidos para cualquier longitud dada (pero no intentes más de 10 o esperarás un tiempo).
Desafíos relacionados
fuente
N
), siempre que no resulte ser bastante trivial y fui demasiado estúpido para encontrarla.Respuestas:
CJam,
6866 bytesPruébalo en línea.
Este es mi primer programa CJam. Comenzó como un puerto de mi solución Perl e inicialmente tenía más de 130 bytes de longitud. Más sugerencias de golf son bienvenidas.
Al igual que con mi programa Perl, consta de dos partes.
Para depurar las matrices creadas por la Parte 1 add
]_`o~
entre las partes 1 y 2. Si n es5
, las matrices se vería así:[[1 1 1 1 1 1] [1 2 3 4 5] [2 5 10 17] [5 15 37] [15 52]]
. Los 0 índices de cada matriz no se usan, simplemente lo hacen más fácil al no tener que calcular las compensaciones. Las matrices se calculan así:Mantiene una copia de la matriz anterior mientras calcula la siguiente. Las matrices se leen y se descartan en orden inverso en la Parte 2.
fuente
Pitón 2, 153
Utiliza el orden alfabético y la indexación basada en 0.
Deje que
l
denote la longitud de un sufijo de las letras ya
denote el número de letras distintas que se usaron en la parte anterior. Entonces, una funciónp(l,a)
que calcula la cantidad de formas de seleccionar las letras restantes podría ser de 40 bytes:Sin embargo, esto es demasiado lento para el desafío, por lo que los valores necesarios se calculan previamente y se almacenan en la
u
matriz. En cada etapa del cálculo, si la siguiente letra es una de lasa
ya utilizadas, n = k * p (l - 1, a) + n ' donde k es la letra del alfabeto indexada en 0 y n' es El valor den
para la siguiente llamada de función, que contiene la información sobre las letras restantes. Si se usa una nueva letra, entonces n = a * p (l - 1, a) + n ' .fuente
Haskell (GHC 7.10), 150 bytes
El operador
n # i
calcula eli
esquema de longitud de la rima th (indexado a cero)n
. Se ejecuta en operaciones O (n²) (entero grande), aprovechando las listas infinitas perezosas de Haskell para la memorización automática. Ejecuciones de muestra:(Si el N máximo fuera 25 en lugar de 26,
.fromEnum
podría eliminarse, porque B (25) cabe en un bit de 64 bitsInt
).fuente
Perl 257 + 1 (bandera -p) = 258Perl 182 + 10 (-pMbignum flags) = 192
¡Gracias a dev-nul por guardar muchos bytes! Ahora lo he reescrito en base a lo que aprendí al hacer la versión de CJam.
Calcula la rima en orden alfabético ascendente, 0 indexado.
Dos partes: la Parte 1 es
12890 bytes y calcula una matriz para la Parte 2. La Parte 2 es12992 bytes y hace algunas matemáticas simples para calcular cada letra.Si pudiera deshacerme de la matriz y reemplazarla con dos números simples, ¡podría calcular una sola ruta a través de la matriz para cada número y ahorrar muchos bytes!Al parecer, esa idea no funciona!Desafortunadamente, noi
genera las rimas correctas para valores superiores a 9007199254740992, ¡pero funciona maravillosamente para valores bajos!He agregado la biblioteca Bignum a un costo de 11 bytes.Se ejecuta desde la línea de comandos conperl -pMbignum bell-rhyme.pl
.-pMbignum
= 10 bytes. También es muy rápido para cualquier valor de entrada.fuente
Oracle SQL 11,2,
412284283 bytesDesafortunadamente, solo tiene una longitud de 8. Cualquier valor mayor da como resultado: ORA-01489: el resultado de la concatenación de cadenas es demasiado largo
Sin golf
La vista a genera: las letras i en la columna a y su valor en b.
La vista recursiva v toma la cadena que se construye como parámetro v, el valor de la última letra usada en c y el valor de la letra más grande usada en n. El parámetro n es igual a la longitud de la cadena sin ninguna letra duplicada, para eso está la expresión regular.
Una letra es válida si su valor es <= el valor de la letra más grande ya utilizada o si es la siguiente letra que se utilizará.
De alguna manera, la consulta necesita la parte LENGTH (s) <: n para ejecutarse, me falta algo en cómo funciona la consulta.
El SELECT principal se encarga de filtrar las entradas no válidas y las cadenas más cortas creadas antes de alcanzar la longitud objetivo.
Versión de 412 bytes
No intente la consulta de 412 bytes con 26. Pone la base de datos en modo restringido, al menos en mi versión xe que se ejecuta en un contenedor docker en un macbook. Podría probarme los exadata en el trabajo, pero lamentablemente todavía necesito trabajar para vivir.
fuente
Mathematica, 136 bytes
Para completar, aquí está mi implementación de referencia de golf. A diferencia de las respuestas existentes, esto no se ejecuta en tiempo polinómico (es exponencial
N
con la base 2), pero cumple con la restricción de tiempo (el peor de los casos aún se ejecutaría en menos de media hora).La idea es esta:
Para cada esquema de rima podemos identificar las posiciones donde el carácter máximo hasta ahora aumenta:
Podemos tratar esas marcas como un número binario que facilita la iteración sobre todas esas estructuras. Necesitamos iterar de 2 n-1 a 2 n (o al revés), que es de donde proviene la complejidad exponencial del tiempo.
i
, lo restamosi
. De lo contrario, hemos encontrado la estructura del esquema de rima solicitado.i
(o lo que queda de ella) como un número de base mixta, donde los pesos de los dígitos están determinados por el número de caracteres permitidos en las posiciones restantes.Me pregunto si esto permitiría una solución más corta en algunos de los otros idiomas que se enviaron, ya que no requiere ninguna memorización o precomputación.
fuente