Fondo
Incident es un lenguaje de programación bastante inusual, ya que su lista de tokens no está predeterminada, sino que se infiere de la entrada. Como tal, tokenizar un programa de Incidentes puede ser bastante difícil, especialmente si desea hacerlo de manera eficiente. Esta tarea se trata de hacerlo tú mismo.
La tarea
Su programa recibirá una cadena como entrada. Aquí está el algoritmo que Incident usa para tokenizarlo:
- Identifique todas las cadenas que ocurren como una subcadena de la entrada de exactamente tres maneras (es decir, hay exactamente tres ocurrencias de esa cadena dentro de la entrada).
- Descarte cualquiera de estas cadenas que sean una subcadena de otra cadena (por ejemplo, para la entrada
ababab
, la única cadena restante seríaab
, noa
ob
, porquea
yb
son ambas subcadenas deab
). - Deseche cualquier cadena que se superponga dentro de la entrada. (Por ejemplo,
aaaa
contiene exactamente tres copias deaa
, pero estas copias se superponen en el segundo y tercer caracteres, por lo que se descartarán. Del mismo modo, enabababa
, hay tres copias deab
y tres copias deba
, pero los caracteres del segundo al sexto están en el la superposición de unaab
yba
, por lo tantoab
, yba
serían descartados). - Las cadenas que quedan en este punto son los tokens utilizados por el programa. Tokenice la entrada original en una secuencia de estos tokens (debido al descarte en el paso anterior, solo habrá una forma de hacerlo). Los caracteres de la entrada que no forman parte de ningún token se tratan como comentarios y se descartan.
Su programa tiene que tomar una cadena como entrada y devolver la tokenización correspondiente de la cadena (una lista de tokens, cada uno de los cuales se expresa como cadenas) como salida. Además, esto debe hacerse al menos de manera moderadamente eficiente; específicamente, el programa tiene que ejecutarse en tiempo cuadrático ("O (n²)") o mejor. (Por cierto, es casi seguro que sea posible ir más rápido que el cuadrático, pero este no es el algoritmo más rápido , así que siéntase libre de usar el algoritmo más exhaustivo que pueda encontrar que se ajuste a los límites de complejidad).
Aclaraciones
- Aunque los programas de incidentes pueden contener, en teoría, cualquiera de los 256 octetos, es aceptable para este desafío que su programa maneje solo entradas formadas de ASCII imprimible (incluyendo espacio), además de nueva línea y tabulación. (Todos los programas de incidentes conocidos se limitan a este subconjunto). Tenga en cuenta que space / newline / tab no son especiales y pueden aparecer en medio de tokens; El incidente trata los 256 octetos como opacos.
- La definición de "tiempo cuadrático" es "si el tamaño de la entrada se duplica, el programa se ejecutará más lentamente en no más de una constante más un factor de 4", es decir, si t ( x ) es el tiempo máximo que tarda su programa en procesar una entrada de tamaño x , entonces debe haber alguna constante k tal que t (2 x ) <4 t ( x ) + k para todo x . Tenga en cuenta que comparar cadenas requiere un tiempo proporcional a la longitud de las cadenas.
- Teóricamente, su programa debería ser capaz de manejar programas de entrada de cualquier longitud si se ejecuta en una variante (posiblemente hipotética) de su idioma que tiene memoria ilimitada y utiliza enteros ilimitados (está bien si el programa no logra este objetivo cuando se ejecuta en la práctica debido a los enteros o la memoria del lenguaje en realidad son finitamente grandes). Puede suponer (con el propósito de calcular la complejidad) que los enteros que no son mayores que la longitud de la entrada se pueden comparar en tiempo constante (aunque tenga en cuenta que si usa valores más grandes, por ejemplo, debido a la conversión de la entrada en un entero único, tomarán un tiempo para comparar proporcionalmente al número de dígitos que tienen).
- Puede usar cualquier algoritmo que se ajuste a los límites de complejidad, incluso si no sigue los mismos pasos que el algoritmo publicado anteriormente, siempre que produzca los mismos resultados.
- Este rompecabezas se trata de tokenizar la entrada, no se trata de formatear la salida. Si la forma más natural de generar una lista en su idioma implica un formato ambiguo (por ejemplo, separado por una nueva línea cuando las cadenas contienen nuevas líneas literales, o sin delimitadores entre las cadenas), no se preocupe por el hecho de que la salida termina siendo ambigua ( siempre y cuando la lista esté realmente construida). Es posible que desee hacer una segunda versión de su envío que produzca resultados inequívocos, para ayudar en las pruebas, pero la versión original es la versión que cuenta para la puntuación.
Caso de prueba
Para la siguiente cadena de entrada:
aaabcbcbcdefdfefedghijghighjkllkklmmmmonono-nonppqpq-pqprsrsrstststuvuvu
su programa debe producir la siguiente lista de resultados:
a a a bc bc bc d e f d f e f e d gh gh gh k l l k k l pq pq pq u u u
Condición de victoria
Este es el código de golf , por lo que gana el programa válido más corto (es decir, el comportamiento correcto de entrada / salida y lo suficientemente rápido para ejecutarse), medido en bytes.
Respuestas:
C (gcc), 324 bytes
La función
f
toma una cadena terminada en nulo e imprime los tokens en stdout. Todas las líneas nuevas se pueden eliminar del siguiente código.Esta versión anterior de 376 bytes es un poco más fácil de leer; la explicación a continuación se aplica a ello.
k(0)
genera la tablat
para el patrónp
para el algoritmo Knuth – Morris – Pratt.K(c)
procesa el siguiente carácterc
de la cadena de búsqueda y las actualizacionesm
,p
cuya longitud del prefijo más grande se puede encontrar terminando en el carácter procesado más recientemente.En el primer
for
bucle, para cada índicea
en la cadena, contamos el número de veces que cada valor posiblem
ocurre cuando se busca en la cadena completa la subcadena que comienza ena
. Luego buscamos el más grande del
tal manera que lal
subcadena de longitud que comienza ena
exactamente 3 veces. Si es lo suficientemente corto como para estar completamente contenido por una cadena encontrada para un anteriora
, lo ignoramos. Si se superpone, eliminamos la cadena anterior dez
la matriz que registra los tokens que se guardarán. De lo contrario, su longitud se almacena enz
.Luego, usamos KMP nuevamente para buscar en la cadena los tokens registrados
z
. Si uno de ellos se encuentra en una ubicación con una entrada 0z
, sabemos que este token se eliminó debido a una superposición. Si el token no se eliminó, se imprime.fuente
O(n^2)
o más rápido. Y ¿por qué hay!!
en!!z[x-m]
?*Z
es la longitud del próximo token que debe convertirse en 0 si alguna de las otras ocurrencias del token tiene el valor 0 en su índice en la matriz, o de lo contrario mantiene el mismo valor (en ese caso!!z[x-m]
debería ser 1.!!
está ahí.!!x
debería seguir siendox
, o invoca un truco que no conozco?!!x
hacex
un booleano que representa su "veracidad". Entonces,!!1 == true
y!!0 == false
. No sé específicamente C, pero así es como suele serJavaScript,
878867842825775752717712704673664650641 bytesGracias a @Kritixi Lithos por ayudar a jugar golf con el código
Gracias a @ User2428118 por jugar golf con 14 bytes
(No funcionará en IE7) (Las líneas nuevas se deben ingresar como "
\n
" y la pestaña como "\t
" en la cadena de entrada, los caracteres Unicode se deben ingresar como\u####
)Pruébalo en línea
Explicación de cómo funciona y código no protegido
Primero, el programa genera matrices Knuth Morris Pratt para cada subcadena posible;
Luego, el programa encuentra las longitudes máximas de coincidencia en cada índice de la palabra con cada subcadena. (este es el tiempo O (n ^ 2))
El programa usa estos datos para encontrar las subcadenas más largas que aparecen tres veces para cada carácter inicial de la cadena.
El programa utiliza estos datos para eliminar todas las subcadenas que no aparecen exactamente tres veces y todas las subcadenas de las subcadenas válidas más largas.
A continuación, el programa establece todas las subcadenas superpuestas o parciales que se eliminarán.
Para cada uno de los valores a eliminar, también se eliminan todas las subcadenas equivalentes.
Finalmente, el programa une la matriz de subcadenas y la genera.
fuente
while
yif
bloques que tienen sólo un 1 dentro de la declaración de ellos. Puede quitar las llaves{}
alrededor de esas declaraciones. Por ejemplo,if(word.charAt(index+i)==word.charAt(index+j)){j++;}
puede llegar a serif(word.charAt(index+i)==word.charAt(index+j))j++;
&&
s para reemplazar lasif
declaraciones, movía las declaraciones en bucles para que terminaran con una declaración debajo de ellas para poder quitar llaves. Usé ternaries para reemplazar algunas declaraciones if. Moví cosas y terminé en 946 bytes . Si no entiendes algo que hice, no