レーベンシュタイン距離


39

このような編集距離の質問は数多くありますが、レーベンシュタイン距離を計算するプログラムを書くのは簡単な質問ではありません。

博覧会

2つの文字列間のレーベンシュタイン編集距離は、1つの単語を別の単語に変換するための挿入、削除、または置換の可能な最小数です。この場合、挿入、削除、および置換の各コストは1です。

例えば、間の距離rollとは、rolling削除が1のコスト、そして私たちは3 characterrsを削除する必要があるため、3です。置換のコストは1なので、tollとの間の距離はtall1です。

ルール

  • 入力は2つの文字列になります。文字列は小文字で、文字のみを含み、空ではなく、最大100文字の長さであると想定できます。
  • 出力は、上記で定義したように、2つの文字列の最小レーベンシュタイン編集距離になります。
  • コードはプログラムまたは関数でなければなりません。名前付き関数である必要はありませんが、レーベンシュタイン距離を直接計算する組み込み関数にすることはできません。他のビルトインが許可されます。
  • これはコードゴルフであるため、最短の答えが勝ちます。

いくつかの例

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

いつものように、問題が不明な場合はお知らせください。幸運と良いゴルフ!

カタログ

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>

回答:



10

Matlabの、177の 163バイト

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)

これは、この式の簡単な実装です。

ここに画像の説明を入力してください

ゴルフをしていない:

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)

得点コードが含まれていない場合は、得点コードを含めてください。それ以外の場合は、ゴルフアウトできる空白がたくさんあると思います。
アレックスA.

1
@AlexA。インデント目的の先頭のスペースと改行はカウントされません(安全に削除できます)。むかしむかしこれは許され、誰も不満を言いませんでした。
edc65

1
@ edc65 メタコンセンサスは、スコア付けされたコードを提供する必要があるということです。
アレックスA.

2
さて、大多数は読めないバージョンを好みます。誰もが実際に何が起こっているかを見たいと思うかもしれない場合に備えて、私はまだここで読みやすいバージョンを許可します=)
flawr

2
ゴルフの提出物(スコアリングされたもの)とゴルフのないバージョンの両方を提供することは一般的な慣行であり、スコアリングされたものを含めることだけが必要です。;)
アレックスA.

7

Python 2、151 140 138バイト

Wikipediaに基づいたレーベンシュタイン距離の再帰的な実装が遅い(11文字のシェービングについては@Kenney、別の2文字については@ Sherlock9に感謝)。

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))

提示されたテストケースに正しい答えを与える:

assert l("tar", "tarp") == 1
assert l("turing", "tarpit") == 4
assert l("antidisestablishmentarianism", "bulb") == 27        
assert l("atoll", "bowl") == 3

1
あなたのような何かをすることによって、3-4バイトかそこらを保存するかもしれないif !n*m:return n if n else mし、別の2によりますreturn 1+min([ f(..), f(..), f(..) - (s[..] == t[..]) ])
ケニー

f(m-1,n-1)-(s[m-1]==t[n-1])代わりにを使用すると、2バイト節約できますf(m-1,n-1)+(s[m-1]!=t[n-1])-1
Sherlock9

20文字オフのゴルフ:codegolf.stackexchange.com/a/102910/60919
FlipTack

5

JavaScriptの(ES6)106 113 122

@Neilの提案に従って保存された16バイトを編集

匿名関数として。

(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

これは、リンクされたウィキペディアの記事のセクション「2行の行列による反復」で説明されているとおり(実際には1行のみが使用されている-配列w)、Wagner-Fischerアルゴリズムのゴルフ実装です。

少ないゴルフ

(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
}

テストスニペット

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>


1
[...[0,...t].keys()]代わりに使用できますか?可能であれば2バイトを節約します。
ニール

1
Nいように見えるが、より短い@Neil。Thx
edc65

1
実際には、別のバイトを保存することもできます、[...[,...t].keys()]私も思う。
ニール

私が使用して別のバイトをオフに剃るために管理[...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)
ニール・

@ニール、ありがとうございます!
edc65

4

Python 2、118バイト

この解決策のゴルフですが、ウィレムが1年間続いているようには見えないので、自分で投稿する必要があります:

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))

repl.itをお試しください

2つの文字列を取り、距離を出力しますSTDOUTmetaで許可)。提案をコメントしてください、これはさらにゴルフすることができると確信しています。


関数内のすべてをラップする必要がありますか?次の2つの使用することができinput()、Sまたはinput().split()
Sherlock9

@ Sherlock9私はそれを試してみましたが、コストが余分に1つのバイトを、私が言うことができる限り
FlipTackを

右、私はあなたが定義する必要があることを忘れていましたsし、tコード内のどこか。気にしないで。良い仕事:D
Sherlock9

ウィレムがなぜ使ったのか分からないm or n。に置き換えることができm+nます。
アーナード

3

AutoIt、333バイト

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

サンプルテストコード:

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

利回り

3
1
4
27

3

k4、66バイト

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

退屈で基本的にアルゴの手に負えない実装。例:

  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

3

真剣に、86 82 78バイト

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

六角ダンプ:

2c232c23606b3b3b3bb03d222b6c229c4022b364293b295b5d6f71bd526975294064293b29405b
5d6f71bd5269752840294029405b5d6f71bd5269337d40293d592b6b6d229c40495269603bbb9f

オンラインで試す

(リンクは別のバージョンへのリンクであることに注意してください。ダウンロード可能なインタープリターでは正常に動作しますが、オンラインインタープリターに関する何かが新しい短いバージョンで壊れているためです。)

これは、最も単純な実装であり、真剣に再帰的な定義を可能にします。メモ化がまったく行われないため、非常に低速です。おそらく、表形式の方法は短くなる可能性があります(レジスタを行として使用することによって)使用できるもの

[]oq`<code>`Ri

適切な2つの引数を持つ関数呼び出しは非常に良い発見でした。

説明:

,#,#                             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

コードが事前要素をエスケープしようとする方法が好きです:)
mınxomaτ15年

3

Pythonの3、267の 216 184 162バイト

この関数は2 x len(word_2)+1、サイズの配列を使用してレーベンシュタイン距離を計算します。

編集:これはウィレムのPython 2の答えに近づきませんが、ここにはあちこちで多くの小さな改良を加えたよりゴルフの答えがあります。

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]

ゴルフをしていない:

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]

3

網膜78 72バイト

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

オンラインでお試しください!

ある意味では、これは純粋な正規表現ソリューションであり、結果は正規表現が一致する位置の数です。理由は...

公正な警告、これは非常に非効率的です。これが機能する方法は、実際の最適化を正規表現エンジンのバックトラッカーにオフロードすることです。これにより、可能な限りすべてのアライメントが単純にブルートフォースされ、可能な限り少ない変更から始まり、追加、削除、および置換で文字列と一致するまでもう1つ許可されます。

もう少し賢明な解決策として、これは1回だけマッチングを行い、ネガティブなルックアラウンドはありません。ここで、結果はgroup内のキャプチャの数であり、たとえばC#で2アクセスできますmatch.Groups[2].Captures.Count。しかし、それでも恐ろしく非効率的です。

説明

上記の2番目のバージョンは、概念的には少し簡単だからです(1つの正規表現の一致であるため)。ここに、私がグループに名前を付けた(またはそれらを非キャプチャーにした)未コメントのバージョンを示し、コメントを追加しました。後読みのコンポーネントは後ろから前に読む必要がありますが、その中の代替物と先読みは前から後ろに読む必要があることに注意してください。うん。

.+                      # 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.
  )*
)

72バイトバージョンとの唯一の違いは、十分な数がない.+最後の位置を見つけてそれらのすべての位置をカウントすることにより、先頭(および最初の2番目のグループ)をドロップできることです。<ops>


3

Haskell67 64バイト

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

オンラインでお試しください!使用例:"turing" # "tarpit"利回り4


説明(以前の67バイトバージョンの場合)

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

これは再帰的な解決策です。2つの文字列eとが与えられるとf、最初にそれらの最初の文字aとを比較しbます。それらが等しい場合には、レーベンシュタイン距離eとは、fレーベンシュタイン距離と同じであるrs、の残りの部分ef最初の文字を除去した後。それ以外の場合は、どちらかaまたはb削除する必要があります。または、一方が他方に置き換えられます。[r#f,e#s,r#s]これらの3つのケースのレーベンシュタインを再帰的に計算しminimum、最小のケースを選択1し、必要な削除または置換操作を説明するために追加されます。

文字列の1つが空の場合、2行目になります。この場合、距離は空でない文字列の長さ、または同等に連結された両方の文字列の長さです。


1
うわー、これは非常に優れたソリューションで、本当にエレガントで短いです。
ggPeti

3

Pythonの3105の 94 93バイト

xnorで-11バイト

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)

ウィキブックスの最短実装のゴルフバージョン。

オンラインでお試しください!


いい解決策。l=関数は再帰的であるため、含まれ、カウントする必要があります。基本ケースをに結合できif b>""<a else len(a+b)ます。
xnor

オペレーターとの素晴らしいプレイ、ありがとう!
movatica

2

Haskell、136バイト

を呼び出しeます。少し遅いantidisestablishmentarianismなど

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)]

2

Jolf、4バイト

ここで試してみてください!

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

昨日、その組み込みを追加しましたが、今日、つまり今まさにこの挑戦を見ました。それでも、この答えは非競合的です。

新しいバージョンでは:

~Li

暗黙の2番目の入力を受け取ります。


コードはプログラムまたは関数でなければなりません。名前付き関数である必要はありませんが、レーベンシュタイン距離を直接計算する組み込み関数にすることはできません。他の組み込み関数は許可されます。
Kevin Cruijssen

ああ、あなたはそれが非競合だと言っているのを見ませんでした。
ケビンクルーッセン

2

GNU Prolog、133バイト

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);!).

タプルを引数として受け取ります。使用例:

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

D = 4

yes

m指定BされA直接、またはその最初の文字を削除して。サブルーチンとしてd使用mして、タプル要素間の編集距離(つまり、一方を他方に変換する一連の編集の距離)を計算ます。次にl、最小値を見つけるための標準的なトリックですd(任意の距離を取り、次に任意の小さな距離を取り、小さくならないまで繰り返します)。


1

Perl、168 166 163バイト

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)

再帰的な実装。に保存し、file.plとして実行し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)


他の2つの実装はどちらも長いです(完全なマトリックス:237バイト、2つの 1行の反復:187)。

  • アップデート166:の()呼び出しを省略しlます。
  • アップデート163:3項でreturn悪用することdoで削除します。


0

C、192バイト

#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;}
---------

詳細

#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;
}

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;}

より読みやすい:

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;
}

0

PowerShell v3 +、247バイト

$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]

私は、LDを含む別の課題を解決するためにこれを作成することになりました。

コメント付きのコード説明。

# 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]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.