Contexte
Incident est un langage de programmation assez inhabituel, dans la mesure où sa liste de jetons n'est pas prédéterminée, mais plutôt déduite de l'entrée. En tant que tel, la tokenisation d'un programme Incident peut être assez difficile, surtout si vous voulez le faire efficacement. Cette tâche consiste à le faire vous-même.
La tâche
Votre programme recevra une chaîne en entrée. Voici l'algorithme utilisé par Incident pour le tokeniser:
- Identifiez toutes les chaînes qui se produisent en tant que sous-chaîne de l'entrée de trois manières exactement (c'est-à-dire qu'il y a exactement trois occurrences de cette chaîne dans l'entrée).
- Supprimez l'une de ces chaînes qui sont une sous-chaîne d'une autre chaîne de ce type (par exemple, pour l'entrée
ababab
, la seule chaîne restante seraitab
, nona
oub
, cara
etb
sont les deux sous-chaînes deab
). - Ignorez toutes les chaînes qui se chevauchent dans l'entrée. (Par exemple,
aaaa
contient exactement trois copies deaa
, mais ces copies se chevauchent aux deuxième et troisième caractères, elles seront donc supprimées. De même, dansabababa
, il y a trois copies deab
et trois copies deba
, mais les deuxième à sixième caractères se trouvent chacun au chevauchement de anab
et aba
, donc les deuxab
etba
seraient rejetés). - Toutes les chaînes qui restent à ce stade sont les jetons utilisés par le programme. Tokenisez l'entrée d'origine dans une séquence de ces jetons (en raison de la suppression à l'étape précédente, il n'y aura qu'une seule façon de le faire). Tous les caractères de l'entrée qui ne font partie d'aucun jeton sont traités comme des commentaires et supprimés.
Votre programme doit prendre une chaîne en entrée et renvoyer la tokenisation correspondante de la chaîne (une liste de jetons, chacun étant exprimé sous forme de chaînes) en sortie. De plus, cela doit être fait au moins modérément efficacement; en particulier, le programme doit fonctionner en temps quadratique ("O (n²)") ou mieux. (Par ailleurs, il est presque certainement possible d'aller plus vite que quadratique, mais ce n'est pas l' algorithme le plus rapide , alors n'hésitez pas à utiliser l'algorithme le plus ters que vous pouvez trouver qui correspond aux limites de la complexité.)
Clarifications
- Bien que les programmes d'incident puissent en théorie contenir n'importe lequel des 256 octets, il est acceptable dans le cadre de ce défi que votre programme ne gère que les entrées formées en ASCII imprimable (y compris l'espace), plus la nouvelle ligne et l'onglet. (Tous les programmes d'incident connus se limitent à ce sous-ensemble). Notez que l'espace / nouvelle ligne / tabulation n'est pas spécial et peut apparaître au milieu des jetons; L'incident traite les 256 octets comme opaques.
- La définition du "temps quadratique" est "si la taille de l'entrée est doublée, le programme fonctionnera plus lentement d'une constante plus un facteur de 4", c'est-à-dire si t ( x ) est le temps maximum que prend votre programme pour traiter une entrée de taille x , alors il doit y avoir une constante k telle que t (2 x ) <4 t ( x ) + k pour tout x . Gardez à l'esprit que la comparaison des chaînes prend du temps proportionnel à la longueur des chaînes.
- Votre programme devrait théoriquement être capable de gérer des programmes d'entrée de n'importe quelle longueur s'il est exécuté dans une variante (éventuellement hypothétique) de votre langue qui a une mémoire illimitée et utilise des nombres entiers illimités (c'est OK si le programme ne parvient pas à atteindre cet objectif lorsqu'il est exécuté dans la pratique en raison de les entiers ou la mémoire du langage étant en fait finement grands). Vous pouvez supposer (aux fins du calcul de la complexité) que les entiers qui ne dépassent pas la longueur de l'entrée peuvent être comparés en temps constant (bien que gardez à l'esprit que si vous utilisez des valeurs plus grandes, par exemple en raison de la conversion de l'entrée en un entier unique, ils mettront un certain temps à comparer proportionnellement au nombre de chiffres dont ils disposent).
- Vous pouvez utiliser n'importe quel algorithme qui respecte les limites de la complexité, même s'il ne suit pas les mêmes étapes que l'algorithme publié ci-dessus, tant qu'il produit les mêmes résultats.
- Ce puzzle consiste à tokeniser l'entrée, pas vraiment à formater la sortie. Si le moyen le plus naturel de produire une liste dans votre langue implique un format ambigu (par exemple, séparé par des sauts de ligne lorsque les chaînes contiennent des sauts de ligne littéraux, ou sans délimiteurs entre les chaînes), ne vous inquiétez pas du fait que la sortie finit par être ambiguë ( tant que la liste est réellement construite). Vous souhaiterez peut-être créer une deuxième version de votre soumission qui produira une sortie sans ambiguïté, pour faciliter les tests, mais la version d'origine est la version qui compte pour la notation.
Cas de test
Pour la chaîne d'entrée suivante:
aaabcbcbcdefdfefedghijghighjkllkklmmmmonono-nonppqpq-pqprsrsrstststuvuvu
votre programme devrait produire la liste de sortie suivante:
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
Condition de victoire
Il s'agit de code-golf , donc le programme valide le plus court (c'est-à-dire un comportement d'entrée / sortie correct et suffisamment rapide pour s'exécuter), mesuré en octets, gagne.
Réponses:
C (gcc), 324 octets
La fonction
f
prend une chaîne terminée par un caractère nul et imprime les jetons sur stdout. Toutes les nouvelles lignes peuvent être supprimées du code ci-dessous.Cette ancienne version de 376 octets est un peu plus facile à lire; l'explication ci-dessous s'y applique.
k(0)
génère la tablet
de modèlep
pour l'algorithme Knuth – Morris – Pratt.K(c)
traiter le caractère suivantc
de la chaîne de recherche et les mises à jourm
, dont la longueur du plus grand préfixep
peut se trouver se terminant par le dernier caractère traité.Dans la première
for
boucle, pour chaque indexa
de la chaîne, nous comptons le nombre de fois où chaque valeur possible dem
se produit lors de la recherche dans la chaîne entière de la sous-chaîne commençant àa
. Ensuite, nous recherchons le plus grandl
tel que lal
sous-chaîne de longueur commençant àa
s'est produite exactement 3 fois. S'il est suffisamment court pour être entièrement contenu par une chaîne trouvée pour un précédenta
, nous l'ignorons. S'il se chevauche, nous supprimons la chaîne précédente dez
, l'enregistrement de tableau dont les jetons seront conservés. Sinon, sa longueur est stockée dansz
.Ensuite, nous utilisons à nouveau KMP pour rechercher dans la chaîne les jetons enregistrés dans
z
. Si l'un d'eux se trouve à un emplacement avec une entrée 0z
, nous savons que ce jeton a été supprimé en raison d'un chevauchement. Si le jeton n'a pas été supprimé, il est imprimé.la source
O(n^2)
ou plus rapide. Et pourquoi y!!
en a-!!z[x-m]
t- il ?*Z
est la longueur du prochain jeton qui doit devenir 0 si l'une des autres occurrences du jeton a la valeur 0 à son index dans le tableau, ou conserve la même valeur sinon (dans ce cas,!!z[x-m]
devrait être 1.!!
est là.!!x
devrait toujours êtrex
, ou cela invoque-t-il une astuce que je ne connais pas?!!x
faitx
un booléen représentant sa "véracité". Alors,!!1 == true
et!!0 == false
. Je ne connais pas C en particulier, mais c'est comme ça que ça se passe habituellementJavaScript,
878867842825775752717712704673664650641 octetsMerci à @Kritixi Lithos d'avoir aidé
à jouer au code Merci à @ User2428118 d'avoir joué au golf 14 octets
(Ne fonctionnera pas dans IE7) (Les sauts de ligne doivent être entrés comme "
\n
" et les tabulations comme "\t
" dans la chaîne d'entrée, tous les caractères Unicode doivent être entrés comme\u####
)Essayez-le en ligne
Explication du fonctionnement et du code non golfé
Premièrement, le programme génère des tableaux Knuth Morris Pratt pour chaque sous-chaîne possible;
Ensuite, le programme trouve les longueurs maximales correspondantes à chaque index unique du mot avec chaque sous-chaîne. (c'est O (n ^ 2) fois)
Le programme utilise ces données pour trouver les sous-chaînes les plus longues qui apparaissent trois fois pour chaque caractère de départ dans la chaîne.
Le programme utilise ces données pour éliminer toutes les sous-chaînes qui n'apparaissent pas exactement trois fois et toutes les sous-chaînes des sous-chaînes valides les plus longues.
Ensuite, le programme définit toutes les sous-chaînes superposées ou partielles comme devant être supprimées.
Pour chacune des valeurs à supprimer, toutes les sous-chaînes équivalentes sont également supprimées.
Enfin, le programme joint le tableau de sous-chaînes et le génère.
la source
while
et desif
blocs qui ne contiennent qu’une seule instruction. Vous pouvez supprimer les accolades{}
autour de ces instructions. Par exemple,if(word.charAt(index+i)==word.charAt(index+j)){j++;}
peut devenirif(word.charAt(index+i)==word.charAt(index+j))j++;
&&
s pour remplacer lesif
instructions, j'ai déplacé les instructions en boucle afin qu'elles se retrouvent avec une instruction sous elles afin de pouvoir supprimer les accolades. J'ai utilisé des ternaires pour remplacer certaines instructions if. J'ai déplacé des trucs et j'ai fini à 946 octets . Si vous ne comprenez pas quelque chose que j'ai fait, n'hésitez pas à me le demander :)