La distance d'édition (ou Levenshtein) entre deux chaînes est le nombre minimal d'insertions, de suppressions et de substitutions de caractère unique nécessaires pour transformer une chaîne en l'autre. Si les deux chaînes ont chacune une longueur n, il est bien connu que cela peut se faire en temps O (n ^ 2) par programmation dynamique. Le code Python suivant effectue ce calcul pour deux chaînes s1
et s2
.
def edit_distance(s1, s2):
l1 = len(s1)
l2 = len(s2)
matrix = [range(l1 + 1)] * (l2 + 1)
for zz in range(l2 + 1):
matrix[zz] = range(zz,zz + l1 + 1)
for zz in range(0,l2):
for sz in range(0,l1):
if s1[sz] == s2[zz]:
matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz])
else:
matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz] + 1)
return matrix[l2][l1]
Dans cette tâche, vous devez vous rapprocher le plus possible du calcul de la distance de montage, mais avec une restriction de mémoire sévère. Votre code est autorisé à définir un tableau contenant 1 000 entiers 32 bits et ce doit être le seul stockage temporaire que vous utilisez dans votre calcul. Toutes les variables et structures de données doivent être contenues dans ce tableau. En particulier, vous ne pourriez pas implémenter l'algorithme ci-dessus comme pour les chaînes de longueur 1000 car il vous faudrait stocker au moins 1 000 000 de numéros. Lorsque votre langue n'a pas naturellement des entiers 32 bits (par exemple Python), vous devez simplement vous assurer de ne jamais stocker un nombre supérieur à 2 ^ 32-1 dans le tableau.
Vous pouvez lire les données en utilisant n'importe quelle bibliothèque standard de votre choix sans vous soucier des restrictions de mémoire dans cette partie. Afin de rendre la compétition équitable pour la partie principale de votre code, vous ne pouvez utiliser que des opérations fonctionnellement équivalentes à celles du langage de programmation C et ne pouvez utiliser aucune bibliothèque externe.
Pour être plus clair, la mémoire pour stocker les données d'entrée ou utilisées par l'interpréteur de votre langue, JVM, etc. ne compte pas dans votre limite et vous ne pouvez rien écrire sur le disque. Vous devez supposer que les données d'entrée sont en lecture seule lorsqu'elles sont en mémoire, vous ne pouvez donc pas les réutiliser pour gagner plus d'espace de travail.
Que dois-je mettre en œuvre?
Votre code doit être lu dans un fichier au format suivant. Il aura trois lignes. La première ligne est la vraie distance d'édition. La seconde est la chaîne 1 et la troisième est la chaîne 2. Je vais la tester avec les exemples de données à https://bpaste.net/show/6905001d52e8 où les chaînes ont une longueur de 10 000 mais elles ne devraient pas être spécialisées pour ces données. Il doit produire la plus petite distance d'édition qu'il puisse trouver entre les deux chaînes.
Vous devrez également prouver que votre distance d'édition provient en fait d'un ensemble valide de modifications. Votre code doit avoir un commutateur qui le transforme en un mode qui peut utiliser plus de mémoire (autant que vous le souhaitez) et génère les opérations d'édition qui donnent votre distance d'édition.
But
Votre score sera le (optimal edit distance/divided by the edit distance you find) * 100
. Pour commencer, notez que vous pouvez obtenir un score en comptant simplement le nombre de discordances entre les deux chaînes.
Vous pouvez utiliser n'importe quelle langue de votre choix, librement disponible et facile à installer sous Linux.
Jeu décisif
Dans le cas d'un bris d'égalité, je vais exécuter votre code sur ma machine Linux et le code le plus rapide l'emporte.
for(int i=0;i<=5;i++)
autorisé car il stocke des donnéesi
?{ uint32_t foo[1000]; for (foo[0] = 0; foo[0] < 5; ++foo[0]) printf("%d ", foo[0]); }
ceci En supposant que votre tableau d'entiers 32 bits sera appeléfoo
.Réponses:
C ++, score 92,35
Algorithme d'estimation: l'algorithme trouve le premier endroit où les deux chaînes diffèrent, puis essaie toutes les permutations d'opération N possibles (insérer, supprimer, remplacer - les caractères qui correspondent sont ignorés sans consommer d'opération). Il note chaque ensemble d'opérations possible en fonction de la distance à laquelle cet ensemble d'opérations correspond avec succès aux deux chaînes, ainsi que du degré de convergence des longueurs de chaîne. Après avoir déterminé l'ensemble des N opérations ayant le score le plus élevé, la première opération de l'ensemble est appliquée, la non-concordance suivante est trouvée et le processus se répète jusqu'à ce que la fin de la chaîne soit atteinte.
Le programme essaie toutes les valeurs de N de 1 à 10 et sélectionne le niveau qui a donné les meilleurs résultats. N = 10 est généralement le meilleur maintenant que la méthode de notation prend en compte la longueur de la chaîne. Des valeurs plus élevées de N seraient probablement encore meilleures, mais prennent exponentiellement plus de temps.
Utilisation de la mémoire: Le programme étant purement itératif, il nécessite très peu de mémoire. Seules 19 variables sont utilisées pour suivre l'état du programme. Celles-ci sont définies par #defines pour agir comme des variables globales.
Utilisation: Le programme est utilisé de la même manière que feersum: le premier paramètre est supposé être le fichier, et tout paramètre supplémentaire indique que les modifications doivent être affichées. Le programme imprime toujours la distance de montage estimée et le score.
Sortie de vérification: sortie de vérification formatée sur trois lignes:
La ligne du haut est la chaîne cible, le milieu est les opérations et le bas est la chaîne en cours d'édition. Les espaces dans la ligne d'opération indiquent que les caractères correspondent. 'R' indique que la chaîne d'édition a son caractère à cette position remplacé par le caractère de la chaîne cible. 'I' indique que la chaîne d'édition a le caractère de la chaîne cible inséré à cette position. 'D' indique que la chaîne d'édition a son caractère à cette position supprimé. Les chaînes d'édition et cible ont des espaces insérés lorsque l'autre a un caractère inséré ou supprimé afin qu'ils s'alignent.
la source
C ++ 75.0
Le programme est conçu pour fonctionner avec des chaînes de texte arbitraires. Ils peuvent être de longueurs différentes tant qu'aucun des deux ne dépasse 13824 caractères. Il utilise 1 897 entiers 16 bits, ce qui équivaut à 949 entiers 32 bits. Au début, je l'écrivais en C, mais j'ai réalisé qu'il n'y avait pas de fonction pour lire une ligne.
Le premier argument de ligne de commande doit être un nom de fichier. S'il existe un deuxième argument, un résumé des modifications est imprimé. La première ligne du fichier est ignorée tandis que les deuxième et troisième sont les chaînes.
L'algorithme est une version doublement bloquée de l'algorithme habituel. Il effectue essentiellement le même nombre d'opérations, mais est bien sûr beaucoup moins précis, car si une sous-séquence commune est divisée sur le bord d'un bloc, une grande partie des économies potentielles sont perdues.
la source
Python,
100J'ai réussi à calculer la distance d'édition parfaitement dans la limite de mémoire allouée. Malheureusement, cette entrée viole deux règles du défi, dans la lettre sinon dans l'esprit.
Tout d'abord, je n'ai pas réellement stocké mes données dans 1 000 pouces 32 bits. Pour les chaînes de 10000 caractères, mon programme crée deux tableaux de 10000 éléments qui ne contiendront que +1, 0 ou -1. À 1,585 bits par nombre ternaire, il serait possible de regrouper ces 20000 trits en 31700 bits, laissant 300 bits plus que suffisant pour mes 7 entiers 16 bits restants.
Deuxièmement, je n'ai pas implémenté le mode requis pour afficher les modifications. J'ai, en variante, implémenté un mode qui imprime la matrice d'édition complète. Il est absolument possible de calculer le chemin d'édition à partir de cette matrice, mais je n'ai pas le temps pour l'instant de l'implémenter.
exemple d'entrée:
exemple de sortie détaillée:
la source