Levenshtein Entfernung

40

Während es viele Bearbeitungsentfernungsfragen gibt, wie diese , gibt es keine einfache Frage, um ein Programm zu schreiben, das die Levenshtein-Entfernung berechnet.

Einige Exposition

Die Levenshtein bearbeiten Abstand zwischen zwei Saiten ist die minimal mögliche Anzahl von Einfügungen, Löschungen oder Ersetzungen, um ein Wort in ein anderes Wort umzuwandeln. In diesem Fall kostet jede Einfügung, Löschung und Ersetzung 1.

Der Abstand zwischen rollund rollingbeträgt beispielsweise 3, da Löschvorgänge 1 kosten und 3 Zeichen gelöscht werden müssen. Der Abstand zwischen tollundtall beträgt 1, da Ersetzungen 1 kosten.

Regeln

  • Die Eingabe besteht aus zwei Zeichenfolgen. Sie können davon ausgehen, dass die Zeichenfolgen in Kleinbuchstaben geschrieben sind, nur Buchstaben enthalten, nicht leer sind und maximal 100 Zeichen lang sind.
  • Die Ausgabe ist die minimale Levenshtein-Bearbeitungsentfernung der beiden Zeichenfolgen, wie oben definiert.
  • Ihr Code muss ein Programm oder eine Funktion sein. Es muss keine benannte Funktion sein, es kann sich jedoch nicht um eine integrierte Funktion handeln, die die Levenshtein-Entfernung direkt berechnet. Andere Einbauten sind erlaubt.
  • Das ist Codegolf, also gewinnt die kürzeste Antwort.

Einige Beispiele

>>> lev("atoll", "bowl")
3
>>> lev("tar", "tarp")
1
>>> lev("turing", "tarpit")
4
>>> lev("antidisestablishmentarianism", "bulb")
27

Wie immer, wenn das Problem unklar ist, lassen Sie es mich bitte wissen. Viel Glück und gutes Golfen!

Katalog

var QUESTION_ID=67474;var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";var COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk";var OVERRIDE_USER=47581;var answers=[],answers_hash,answer_ids,answer_page=1,more_answers=true,comment_page;function answersUrl(index){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+index+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(index,answers){return"http://api.stackexchange.com/2.2/answers/"+answers.join(';')+"/comments?page="+index+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:true,success:function(data){answers.push.apply(answers,data.items);answers_hash=[];answer_ids=[];data.items.forEach(function(a){a.comments=[];var id=+a.share_link.match(/\d+/);answer_ids.push(id);answers_hash[id]=a});if(!data.has_more)more_answers=false;comment_page=1;getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:true,success:function(data){data.items.forEach(function(c){if(c.owner.user_id===OVERRIDE_USER)answers_hash[c.post_id].comments.push(c)});if(data.has_more)getComments();else if(more_answers)getAnswers();else process()}})}getAnswers();var SCORE_REG=/<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;var OVERRIDE_REG=/^Override\s*header:\s*/i;function getAuthorName(a){return a.owner.display_name}function process(){var valid=[];answers.forEach(function(a){var body=a.body;a.comments.forEach(function(c){if(OVERRIDE_REG.test(c.body))body='<h1>'+c.body.replace(OVERRIDE_REG,'')+'</h1>'});var match=body.match(SCORE_REG);if(match)valid.push({user:getAuthorName(a),size:+match[2],language:match[1],link:a.share_link,});else console.log(body)});valid.sort(function(a,b){var aB=a.size,bB=b.size;return aB-bB});var languages={};var place=1;var lastSize=null;var lastPlace=1;valid.forEach(function(a){if(a.size!=lastSize)lastPlace=place;lastSize=a.size;++place;var answer=jQuery("#answer-template").html();answer=answer.replace("{{PLACE}}",lastPlace+".").replace("{{NAME}}",a.user).replace("{{LANGUAGE}}",a.language).replace("{{SIZE}}",a.size).replace("{{LINK}}",a.link);answer=jQuery(answer);jQuery("#answers").append(answer);var lang=a.language;lang=jQuery('<a>'+lang+'</a>').text();languages[lang]=languages[lang]||{lang:a.language,lang_raw:lang.toLowerCase(),user:a.user,size:a.size,link:a.link}});var langs=[];for(var lang in languages)if(languages.hasOwnProperty(lang))langs.push(languages[lang]);langs.sort(function(a,b){if(a.lang_raw>b.lang_raw)return 1;if(a.lang_raw<b.lang_raw)return-1;return 0});for(var i=0;i<langs.length;++i){var language=jQuery("#language-template").html();var lang=langs[i];language=language.replace("{{LANGUAGE}}",lang.lang).replace("{{NAME}}",lang.user).replace("{{SIZE}}",lang.size).replace("{{LINK}}",lang.link);language=jQuery(language);jQuery("#languages").append(language)}}
body{text-align:left!important}#answer-list{padding:10px;width:290px;float:left}#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="language-list"> <h2>Shortest Solution by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr> </thead> <tbody id="languages"> </tbody> </table> </div> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr> </thead> <tbody id="answers"> </tbody> </table> </div> <table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table>

Sherlock9
quelle

Antworten:

8

Pyth, 34 Bytes

J]wf}z=Jsmsm++.DdkXLdkGXLkdGhld-Jk

Demonstration

Dies ist nicht besonders gut golfen und sehr langsam. In einem angemessenen Zeitraum können keine Änderungen mehr vorgenommen werden.

isaacg
quelle
3
Aber es funktioniert, und darauf kommt es an. : P
Conor O'Brien
10

Matlab, 177 163 Bytes

function l=c(a,b);m=nnz(a)+1;n=nnz(b)+1;for i=0:m-1;for j=0:n-1;z=max(i,j);try;z=min([l(i,j+1)+1,l(i+1,j)+1,l(i,j)+(a(i)~=b(j))]);end;l(i+1,j+1)=z;end;end;l=l(m,n)

Dies ist eine einfache Implementierung dieser Formel:

Bildbeschreibung hier eingeben

Ungolfed:

function l=l(a,b);
m=nnz(a)+1;
n=nnz(b)+1;
for i=0:m-1;
    for j=0:n-1;
        z=max(i,j);
        try;
            z=min([l(i,j+1)+1,l(i+1,j)+1,l(i,j)+(a(i)~=b(j))]);
        end;
        l(i+1,j+1)=z;
    end;
end;
l=l(m,n)
fehlerhaft
quelle
Wenn der erzielte Code nicht dem entspricht, den Sie angegeben haben, geben Sie den bewerteten Code an. Ansonsten denke ich, dass es eine Menge Whitespace gibt, die man ausspielen kann.
Alex A.
1
@AlexA. Das führende Leerzeichen und die Zeilenumbrüche für Einrückungszwecke werden nicht gezählt (und können sicher entfernt werden). Es war einmal erlaubt und niemand beschwerte sich.
edc65
1
@ edc65 Der Meta - Konsens ist nun , dass der Code als erzielter sollte zur Verfügung gestellt werden.
Alex A.
2
Na dann, die Mehrheit bevorzugt die unlesbare Version. Ich lasse noch die lesbare Version hier, falls jemand sehen möchte, was eigentlich los ist =)
Fehler
2
Es ist gängige Praxis, sowohl die Golf-Einsendung (die, die erzielt wurde) als auch eine nicht-Golf-Version bereitzustellen. Wir fordern lediglich, dass die erzielte enthalten ist. ;)
Alex A.
7

Python 2, 151 140 138 Bytes

Langsame rekursive Implementierung der Levenshtein-Distanz basierend auf Wikipedia (Dank an @Kenney für die Rasur von 11 Zeichen und @ Sherlock9 für weitere 2).

def l(s,t):
 def f(m,n):
  if m*n<1:return m or n
  return 1+min([f(m-1,n),f(m,n-1),f(m-1,n-1)-(s[m-1]==t[n-1])])
 return f(len(s),len(t))

Die richtigen Antworten für die vorgestellten Testfälle geben:

assert l("tar", "tarp") == 1
assert l("turing", "tarpit") == 4
assert l("antidisestablishmentarianism", "bulb") == 27        
assert l("atoll", "bowl") == 3
Willem
quelle
1
Sie könnten 3-4 Bytes oder so sparen, indem Sie so etwas tun if !n*m:return n if n else m, und weitere 2 Bytes return 1+min([ f(..), f(..), f(..) - (s[..] == t[..]) ]).
Kenney
Sie würden 2 Bytes sparen, indem Sie f(m-1,n-1)-(s[m-1]==t[n-1])anstelle von verwenden f(m-1,n-1)+(s[m-1]!=t[n-1])-1.
Sherlock9
Golfed off 20 Zeichen: codegolf.stackexchange.com/a/102910/60919
FlipTack
5

JavaScript (ES6) 106 113 122

Bearbeiten Sie 16 Bytes, die gemäß @Neil-Vorschlägen gespeichert wurden

Als anonyme Funktion.

(s,t)=>[...s].map((u,i)=>w=w.map((v,j)=>p=j--?Math.min(p,v,w[j]-(u==t[j]))+1:i+1),w=[...[,...t].keys()])|p

Dies ist eine gelungene Implementierung des Wagner-Fischer-Algorithmus, genau wie im verlinkten Wikipedia-Artikel im Abschnitt Iterativ mit zwei Matrixzeilen beschrieben (auch wenn tatsächlich nur eine Zeile verwendet wird - Array w ).

Weniger golfen

(s,t)=>
{
  w = [...[0,...t].keys()];
  for(i = 0; i < s.length; i++)
    w = w.map((v,j)=>
              p = j
              ? Math.min(p+1, v+1, w[j-1] + (s[i]!=t[j-1]))
              : i+1
             );
  return p
}

Testschnipsel

L=(s,t)=>[...s].map((u,i)=>w=w.map((v,j)=>p=j--?Math.min(p,v,w[j]-(u==t[j]))+1:i+1),w=[...[,...t].keys()])|p

console.log=x=>O.textContent+=x+'\n';

[["atoll", "bowl"],["tar", "tarp"]
,["turing", "tarpit"],["antidisestablishmentarianism", "bulb"]]
.forEach(t=>console.log(t+' => '+L(...t)))
<pre id=O></pre>

edc65
quelle
1
Können Sie [...[0,...t].keys()]stattdessen verwenden? Spart 2 Bytes, wenn Sie können.
Neil
1
@Neil das sieht hässlich aus aber es ist kürzer. Thx
edc65
1
Eigentlich kann man ein weiteres Byte speichern, [...[,...t].keys()]funktioniert auch, denke ich.
Neil
Ich habe es geschafft, ein weiteres Byte zu entfernen, indem ich [...s].map():(s,t)=>(w=[...[,...t].keys()],[...s].map((u,i)=>w=w.map((v,j)=>p=j--?Math.min(p,v,w[j]-(s[i-1]==t[j]))+1:i)),p)
Neil
@Neil super, danke nochmal!
Edc65
4

Python 2, 118 Bytes

Ein Golf dieser Lösung , aber es sieht nicht so aus, als wäre Willem schon seit einem Jahr dabei, also muss ich es selbst posten:

def l(s,t):f=lambda m,n:m or n if m*n<1else-~min(f(m-1,n),f(m,n-1),f(m-1,n-1)-(s[m-1]==t[n-1]));print f(len(s),len(t))

Versuchen Sie es mit repl.it

Nimmt zwei Zeichenketten und gibt den Abstand zu STDOUT( durch Meta erlaubt ) aus. Bitte kommentieren Sie Vorschläge, ich bin sicher, dies kann weiter golfen werden.

FlipTack
quelle
Ist es notwendig, alles in eine Funktion zu packen? Könnten Sie zwei input()s oder ein verwenden input().split()?
Sherlock9
@ Sherlock9 Ich habe das versucht, aber es kostet 1 Byte mehr , soweit ich das
beurteilen
Richtig, ich habe vergessen, dass Sie sund tirgendwo im Code definieren müssen. Keine Ursache. Gute Arbeit: D
Sherlock9
Ich bin mir nicht sicher, warum Willem benutzt hat m or n. Sie können es durch ersetzen m+n.
Arnauld
3

AutoIt , 333 Bytes

Func l($0,$1,$_=StringLen,$z=StringMid)
Dim $2=$_($0),$3=$_($1),$4[$2+1][$3+1]
For $5=0 To $2
$4[$5][0]=$5
Next
For $6=0 To $3
$4[0][$6]=$6
Next
For $5=1 To $2
For $6=1 To $3
$9=$z($0,$5,1)<>$z($1,$6,1)
$7=1+$4[$5][$6-1]
$8=$9+$4[$5-1][$6-1]
$m=1+$4[$5-1][$6]
$m=$m>$7?$7:$m
$4[$5][$6]=$m>$8?$8:$m
Next
Next
Return $4[$2][$3]
EndFunc

Beispieltestcode:

ConsoleWrite(l("atoll", "bowl") & @LF)
ConsoleWrite(l("tar", "tarp") & @LF)
ConsoleWrite(l("turing", "tarpit") & @LF)
ConsoleWrite(l("antidisestablishmentarianism", "bulb") & @LF)

Ausbeuten

3
1
4
27
mınxomaτ
quelle
3

k4, 66 Bytes

{$[~#x;#y;~#y;#x;&/.z.s'[-1 0 -1_\:x;0 -1 -1_\:y]+1 1,~(*|x)=*|y]}

Ein langweiliges und im Grunde ungolfiertes Werkzeug der Algo. Ex.:

  f:{$[~#x;#y;~#y;#x;&/.z.s'[-1 0 -1_\:x;0 -1 -1_\:y]+1 1,~(*|x)=*|y]}
  f["kitten";"sitting"]
3
  f["atoll";"bowl"]
3
  f["tar";"tarp"]
1
  f["turing";"tarpit"]
4
  f["antidisestablishmentarianism";"bulb"]
27
Aaron Davies
quelle
3

Im Ernst, 86 82 78 Bytes

,#,#`k;;;░="+l"£@"│d);)[]oq╜Riu)@d);)@[]oq╜Riu(@)@)@[]oq╜Ri3}@)=Y+km"£@IRi`;╗ƒ

Hex Dump:

2c232c23606b3b3b3bb03d222b6c229c4022b364293b295b5d6f71bd526975294064293b29405b
5d6f71bd5269752840294029405b5d6f71bd5269337d40293d592b6b6d229c40495269603bbb9f

Probieren Sie es online

(Beachten Sie, dass sich der Link auf eine andere Version bezieht, da einige Aspekte des Online-Interpreters von der neuen, kürzeren Version abweichen, obwohl dies mit dem herunterladbaren Interpreter problemlos funktioniert.)

Es geht um die einfachste Implementierung Ermöglicht ernsthaft die rekursive Definition. Es ist sehr langsam, weil es überhaupt keine Speicherung macht. Vielleicht könnte die tabellarische Methode kürzer sein (vielleicht durch die Verwendung der Register als Zeilen), aber ich bin ziemlich zufrieden damit, trotz der Unzulänglichkeiten, die die Sprache aufweist. Das kann man gebrauchen

[]oq`<code>`Ri

als richtiger Funktionsaufruf mit zwei Argumenten war das ganz nett zu finden.

Erläuterung:

,#,#                             Read in two arguments, break them into lists of chars
    `                       `;╗ƒ put the quoted function in reg0 and immediately call it
     k;;;                        put the two lists in a list and make 3 copies
         ░                       replace the latter two with one with empty lists removed
          =                      replace two more with 1 if no empty lists removed, else 0
           "..."£@"..."£@        push the two functions described below, moving 
                                 the boolean above them both
                         I       select the correct function based on the condition
                          Ri     call the function, returning the correct distance
                                 for these substrings

   There are two functions that can be called from the main function above. Each expects 
   two strings, i and j, to be on the stack. This situation is ensured by putting 
   those strings in a list and using R to call the functions with that list as the stack.
   The first is very simple:

+l                             Concatenate the strings and take their length.
                               This is equivalent to the length of the longer
                               string, since one of the strings will be empty.

   The second function is very long and complicated. It will do the "insertion, deletion, 
   substitution" part of the recursive definition. Here's what happens in 4 parts:

│d);)                          After this, the stack is top[i-,j,i,j,ci,i-], where i- is 
                               list i with its last character, ci, chopped off.
     []oq                      this puts i- and j into a list so that they can be passed
                               as arguments recursively into the main function
         ╜Riu                  this calls the main function (from reg0) with the args
                               which will return a number to which we add 1 to get #d,
                               the min distance if we delete a character
)@d);)@                        After this, the stack is top[i,j-,ci,i-,#d,cj,j-], where 
                               j- and cj are the same idea as i- and ci
       []oq╜Riu                listify arguments, recurse and increment to get #i
                               (distance if we insert)
(@)@)@                         After this, the stack is top[i-,j-,#d,cj,#i,ci]
      []oq╜Ri                  listify arguments, recurse to get min distance between 
                               them but we still need to add 1 when we'd need to 
                               substitute because the chars we chopped off are different
(((@)                          After this, the stack is top[cj,ci,#s,#d,#i]
     =Y                        1 if they are not equal, 0 if they are
       +                       add it to the distance we find to get the distance
                               if we substitute here
        k                      put them all in a list
         m                     push the minimum distance over the three options
Quintopie
quelle
Mir gefällt, wie der Code versucht, dem
Vorelement
3

Python 3, 267 216 184 162 Bytes

Diese Funktion berechnet die Levenshtein-Distanz unter Verwendung eines Arrays von 2 x len(word_2)+1 in der Größe ist.

Bearbeiten: Dies kommt der Antwort von Willem's Python 2 nicht nahe, aber hier ist eine golfenere Antwort mit vielen kleinen Verbesserungen hier und da.

def e(p,q):
 m=len(q);r=range;*a,=r(m+1);b=[1]*-~m
 for i in r(len(p)):
  for j in r(m):b[j+1]=1+min(a[j+1],b[j],a[j]-(p[i]==q[j]))
  a,b=b,[i+2]*-~m
 return a[m]

Ungolfed:

def edit_distance(word_1,word_2):
    len_1 = len(word_1)
    len_2 = len(word_2)
    dist = [[x for x in range(len_2+1)], [1 for y in range(len_2+1)]]
    for i in range(len_1):
        for j in range(len_2):
            if word_1[i] == word_2[j]:
                dist[1][j+1] = dist[0][j]
            else:
                deletion = dist[0][j+1]+1
                insertion = dist[1][j]+1
                substitution = dist[0][j]+1
                dist[1][j+1] = min(deletion, insertion, substitution)
        dist[0], dist[1] = dist[1], [i+2 for m in range(len_2+1)]
    return dist[0][len_2]
Sherlock9
quelle
3

Retina , 78 72 Bytes

&`(.)*$(?<!(?=((?<-4>\4)|(?<-1>.(?<-4>)?))*,(?(4),))^.*,((.)|(?<-1>.))*)

Probieren Sie es online!

In gewisser Weise handelt es sich hierbei um eine reine Regex-Lösung, bei der das Ergebnis die Anzahl der Positionen ist, an denen der Regex übereinstimmt. Weil warum nicht...

Faire Warnung, das ist super ineffizient. Das funktioniert so, dass die eigentliche Optimierung auf den Backtracker der Regex-Engine verlagert wird, der einfach alle möglichen Ausrichtungen erzwingt, wobei mit möglichst wenigen Änderungen begonnen wird und eine weitere zulässig ist, bis es möglich ist, die Zeichenfolgen mit Hinzufügungen, Löschungen und Ersetzungen abzugleichen .

Für eine etwas vernünftigere Lösung führt diese nur einmal das Matching durch und hat keine negativen Lookarounds. Hier ist das Ergebnis die Anzahl der Captures in der Gruppe 2, auf die Sie match.Groups[2].Captures.Countbeispielsweise in C # zugreifen können . Es ist immer noch schrecklich ineffizient.

Erläuterung

Ich erkläre die zweite Version oben, weil sie konzeptionell etwas einfacher ist (da es sich nur um ein einzelnes Regex-Match handelt). Hier ist eine ungolfed Version, in der ich die Gruppen benannt (oder nicht erfasst) und Kommentare hinzugefügt habe. Denken Sie daran, dass die Komponenten in einem Lookbehind von hinten nach vorne gelesen werden sollten, aber Alternativen und Lookaheads in diesen Komponenten sollten von vorne nach hinten gelesen werden. Ja.

.+                      # Ensures backtracking from smallest to largest for next repetition
(?<ops>(?<distance>.))* # This puts the current attempted distances onto two different stacks,
                        # one to work with, and one for the result.
$                       # Make sure the lookbehind starts from the end.
(?<=                    # The basic idea is now to match up the strings character by character,
                        # allowing insertions/deletions/substitutions at the cost of one capture
                        # on <ops>. Remember to read from the bottom up.
  (?=                   # Start matching forwards again. We need to go through the other string
                        # front-to-back due to the nature of the stack (the last character we
                        # remembered from the second string must be the first character we check
                        # against in the first string).
    (?:
      (?<-str>\k<str>)  # Either match the current character against the corresponding one from
                        # the other string.
    |
      (?<-ops>          # Or consume one operation to...
        .               # consume a character without matching it to the other string (a deletion)
        (?<-str>)?      # optionally dropping a character from the other string as well 
                        # (a substitution).
      )
    )*                  # Rinse and repeat.
    ,(?(str),)          # Ensure we reached the end of the first string while consuming all of the 
                        # second string. This is only possible if the two strings can be matched up 
                        # in no more than <distance> operations.
  )
  ^.*,                  # Match the rest of string to get back to the front.
  (?:                   # This remembers the second string from back-to-front.
    (?<str>.)           # Either capture the current character.
  |
    (?<-ops>.)          # Or skip it, consuming an operation. This is an insertion.
  )*
)

Der einzige Unterschied zur 72-Byte-Version besteht darin, dass wir die führende .+(und die zweite Gruppe am Anfang) löschen können, indem wir Positionen am Ende finden, an denen wir nicht genug haben, <ops>und alle diese Positionen zählen.

Martin Ender
quelle
3

Haskell , 67 64 Bytes

e@(a:r)#f@(b:s)=sum[1|a/=b]+minimum[r#f,e#s,r#s]
x#y=length$x++y

Probieren Sie es online! Anwendungsbeispiel: "turing" # "tarpit"Erträge 4.


Erläuterung (für die vorherige 67-Byte-Version)

e@(a:r)#f@(b:s)|a==b=r#s|1<3=1+minimum[r#f,e#s,r#s]
x#y=length$x++y

Dies ist eine rekursive Lösung. Bei zwei gegebenen Zeichenfolgen eund fvergleichen wir zuerst die ersten Zeichen aund b. Wenn sie gleich sind, ist der Levenshtein-Abstand von eund fderselbe wie der Levenshtein-Abstand von rund s, der Rest von eund fnach dem Entfernen der ersten Zeichen. Andernfalls muss entweder aoder bentfernt werden, oder einer wird durch den anderen ersetzt. [r#f,e#s,r#s]Berechnet rekursiv das Levenshtein für diese drei Fälle, minimumwählt das kleinste aus und 1wird addiert, um den erforderlichen Vorgang zum Entfernen oder Ersetzen zu berücksichtigen.

Wenn eine der Zeichenfolgen leer ist, befinden wir uns in der zweiten Zeile. In diesem Fall entspricht der Abstand lediglich der Länge der nicht leeren Zeichenfolge oder äquivalent der Länge beider miteinander verketteter Zeichenfolgen.

Laikoni
quelle
1
Wow, das ist eine wirklich gute Lösung, sehr elegant und kurz.
ggPeti
3

Python 3 , 105 94 93 Bytes

-11 Bytes von xnor

l=lambda a,b:b>""<a and min(l(a[1:],b[1:])+(a[0]!=b[0]),l(a[1:],b)+1,l(a,b[1:])+1)or len(a+b)

Golf-Version der kürzesten Implementierung auf Wikibooks .

Probieren Sie es online!

movatica
quelle
Gute Lösung. Das l=muss eingeschlossen und gezählt werden, da die Funktion rekursiv ist. Sie können die Basenfälle zu kombinieren if b>""<a else len(a+b).
27.
Schönes Spiel mit den Betreibern, danke!
Movatica
2

Haskell, 136 Bytes

Rufen Sie an e. Etwas langsam antidisestablishmentarianismusw.

l=length
e a b=v a(l a)b(l b)
v a i b j|i*j==0=i+j|0<1=minimum[1+v a(i-1)b j,1+v a i b(j-1),fromEnum(a!!(i-1)/=b!!(j-1))+v a(i-1)b(j-1)]
Leif Willerts
quelle
2

Jolf, 4 Bytes

Probieren Sie es hier aus!

~LiI
~L   calculate the Levenshtein distance of
  i   input string
   I  and another input string

Ich habe das gestern eingebaut, aber diese Herausforderung heute gesehen, also erst jetzt. Dennoch ist diese Antwort nicht konkurrierend.

In einer neueren Version:

~Li

Nimmt implizite zweite Eingabe.

Conor O'Brien
quelle
" Ihr Code muss ein Programm oder eine Funktion sein. Es muss keine benannte Funktion sein, aber es kann keine eingebaute Funktion sein, die die Levenshtein-Entfernung direkt berechnet . Andere eingebaute Funktionen sind zulässig. "
Kevin Cruijssen
Ah, hast du nicht gesehen, dass es nicht konkurrierend ist? Schreib es besser in den Titel oder füge ein gültiges Programm / eine gültige Funktion hinzu, ohne eingebaut zu sein.
Kevin Cruijssen
2

GNU Prolog, 133 Bytes

m([H|A],B):-B=A;B=[H|A].
d([H|A]-[H|B],D):-d(A-B,D).
d(A-B,D):-A=B,D=0;D#=E+1,m(A,X),m(B,Y),d(X-Y,E).
l(W,D):-d(W,D),(E#<D,l(W,E);!).

Nimmt ein Tupel als Argument. Anwendungsbeispiel:

| ?- l("turing"-"tarpit",D).

D = 4

yes

mGibt an, dass Bist , Aentweder direkt oder mit seinem ersten Zeichen entfernt. dVerwendungen mals ein Unterprogramm zur Berechnung eines Bearbeitungs Abstandes zwischen dem Tupel Elemente (dh des Abstandes von einer Reihe von Bearbeitungen man , daß umwandelt in die anderen). Dann list ein Standardtrick zum Finden des Minimums von d(Sie nehmen eine beliebige Strecke, dann nehmen Sie eine beliebige kleinere Strecke, wiederholen Sie, bis Sie nicht kleiner werden können).


quelle
1

Perl, 168 166 163 Bytes

sub l{my($S,$T,$m)=(@_,100);$S*$T?do{$m=++$_<$m?$_:$m for l($S-1,$T),l($S,--$T),l(--$S,$T)-($a[$S]eq$b[$T]);$m}:$S||$T}print l~~(@a=shift=~/./g),~~(@b=shift=~/./g)

Rekursive Implementierung. In a speichern file.plund ausführen als perl file.pl atoll bowl.

sub l {
    my($S,$T,$m)=(@_,100);

    $S*$T
    ? do {
        $m = ++$_ < $m ? $_ : $m
        for
            l($S-1,   $T),
            l($S  , --$T),
            l(--$S,   $T) - ($a[$S] eq $b[$T])
        ;    
        $m
    }
    : $S||$T
}
print l~~(@a=shift=~/./g),~~(@b=shift=~/./g)


Die beiden anderen Implementierungen sind länger (vollständige Matrix: 237 Bytes, zwei einzeilige Iterationen: 187).

  • Update 166 : omit ()in Berufung l.
  • update 163 : returndurch missbrauch doin trinary beseitigen.
Kenney
quelle
0

C 192 Bytes

#define m(x,y) (x>y?x:y)
#define r(x,y) l(s,ls-x,t,lt-y)
int l(char*s,int ls,char*t,int lt){if(!ls)return lt;if(!lt)return ls;a=r(1,1);if(s[ls]==t[ls])return a;return m(m(r(0,1),r(1,0)),a)+1;}
---------

Detailliert

#include <stdio.h>

#define m(x,y) (x>y?x:y)
#define f(x) char x[128];fgets(x,100,stdin)
#define r(x,y) l(s,ls-x,t,lt-y)

int l(char*s,int ls,char*t,int lt)
{
    if(!ls) return lt;
    if(!lt) return ls;

    int a = r(1,1);
    if(s[ls]==t[ls]) return a;

    return m(m(r(0,1),r(1,0)),a)+1;
}

int main(void)
{
    f(a);
    f(b);
    printf("%d", l(a,strlen(a),b,strlen(b)));
    return 0;
}
Khaled.K
quelle
0

C # 215 210 198

public int L(string s,string t){int c,f,a,i,j;var v=new int[100];for(c=i=0;i<s.Length;i++)for(f=c=i,j=0;j<t.Length;j++){a=c;c=f;f=i==0?j+1:v[j];if(f<a)a=f;v[j]=c=s[i]==t[j]?c:1+(c<a?c:a);}return c;}

besser lesbar:

public int L(string s,string t){
    int c,f,a,i,j;
    var v=new int[100];
    for(c=i=0;i<s.Length;i++)
        for(f=c=i,j=0;j<t.Length;j++){
            a=c;
            c=f;
            f=(i==0)?j+1:v[j];
            if (f<a) a=f;
            v[j]=c=(s[i]==t[j])?c:1+((c<a)?c:a);
        }
    return c;
}
Kriegsbeil - Setzen Sie Monica wieder ein
quelle
0

PowerShell v3 +, 247 Bytes

$c,$d=$args;$e,$f=$c,$d|% le*;$m=[object[,]]::new($f+1,$e+1);0..$e|%{$m[0,$_]=$_};0..$f|%{$m[$_,0]=$_};1..$e|%{$i=$_;1..$f|%{$m[$_,$i]=(($m[($_-1),$i]+1),($m[$_,($i-1)]+1),($m[($_-1),($i-1)]+((1,0)[($c[($i-1)]-eq$d[($_-1)])]))|sort)[0]}};$m[$f,$e]

Am Ende habe ich das gemacht, um weitere Herausforderungen mit LDs zu lösen.

Codeerklärung mit Kommentaren.

# Get both of the string passed as arguments. $c being the compare string
# and $d being the difference string. 
$c,$d=$args

# Save the lengths of these strings. $e is the length of $c and $f is the length of $d
$e,$f=$c,$d|% le*

# Create the multidimentional array $m for recording LD calculations
$m=[object[,]]::new($f+1,$e+1)

# Populate the first column 
0..$e|%{$m[0,$_]=$_}

# Populate the first row
0..$f|%{$m[$_,0]=$_}

# Calculate the Levenshtein distance by working through each position in the matrix. 
# Working the columns
1..$e|%{
    # Save the column index for use in the next pipeline
    $i=$_

    # Working the rows.
    1..$f|%{
        # Calculate the smallest value between the following values in the matrix relative to this one
        # cell above, cell to the left, cell in the upper left. 
        # Upper left also contain the cost calculation for this pass.    
        $m[$_,$i]=(($m[($_-1),$i]+1),($m[$_,($i-1)]+1),($m[($_-1),($i-1)]+((1,0)[($c[($i-1)]-eq$d[($_-1)])]))|sort)[0]
    }
}
# Return the last element of the matrix to get LD 
$m[$f,$e]
Matt
quelle