Khoảng cách Levenshtein


39

Mặc dù có nhiều câu hỏi về khoảng cách chỉnh sửa, chẳng hạn như câu hỏi này , không có câu hỏi đơn giản nào để viết chương trình tính khoảng cách Levenshtein.

Một số triển lãm

Khoảng cách chỉnh sửa Levenshtein giữa hai chuỗi là số lần chèn, xóa hoặc thay thế tối thiểu có thể để chuyển đổi một từ thành một từ khác. Trong trường hợp này, mỗi lần chèn, xóa và thay thế có chi phí là 1.

Ví dụ: khoảng cách giữa rollrollinglà 3, vì việc xóa có giá 1 và chúng ta cần xóa 3 ký tự. Khoảng cách giữa tolltalllà 1, vì chi phí thay thế là 1.

Quy tắc

  • Đầu vào sẽ là hai chuỗi. Bạn có thể giả sử rằng các chuỗi là chữ thường, chỉ chứa các chữ cái, không trống và có độ dài tối đa 100 ký tự.
  • Đầu ra sẽ là khoảng cách chỉnh sửa Levenshtein tối thiểu của hai chuỗi, như được định nghĩa ở trên.
  • Mã của bạn phải là một chương trình hoặc một chức năng. Nó không cần phải là một hàm được đặt tên, nhưng nó không thể là một hàm dựng sẵn có thể tính trực tiếp khoảng cách Levenshtein. Xây dựng khác được cho phép.
  • Đây là mã golf, vì vậy câu trả lời ngắn nhất sẽ thắng.

Vài ví dụ

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

Như mọi khi, nếu vấn đề không rõ ràng, xin vui lòng cho tôi biết. Chúc may mắn và chơi golf tốt!

Mục lục

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>

Câu trả lời:


8

Bình thường, 34 byte

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

Trình diễn

Điều này không đặc biệt tốt cho golf, và rất chậm. Nó không thể xử lý bất cứ điều gì qua 2 thay đổi trong một khoảng thời gian hợp lý.


3
Nhưng nó hoạt động, và đó là những gì được tính. : P
Conor O'Brien

10

Matlab, 177 163 byte

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)

Đây là một cách thực hiện đơn giản của công thức này:

nhập mô tả hình ảnh ở đây

Ung dung:

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)

Nếu mã được ghi không phải là những gì bạn đã bao gồm, vui lòng bao gồm mã được ghi. Mặt khác, tôi nghĩ rằng có rất nhiều khoảng trắng có thể được đánh gôn.
Alex A.

1
@AlexA. không gian hàng đầu và dòng mới cho mục đích thụt đầu dòng không được tính (và có thể được gỡ bỏ một cách an toàn). Mở ra một thời gian điều này được cho phép và không ai phàn nàn.
edc65

1
@ edc65 Sự đồng thuận meta bây giờ là mã được ghi phải được cung cấp.
Alex A.

2
Vậy thì, phần lớn thích phiên bản không thể đọc được. Tôi vẫn để phiên bản có thể đọc được ở đây, trong trường hợp bất kỳ ai cũng có thể muốn xem những gì đang thực sự xảy ra =)
flawr

2
Đó là thực tế phổ biến để cung cấp cả bài nộp golf (bài được ghi) cũng như phiên bản không được chỉnh sửa, chúng tôi chỉ yêu cầu phải bao gồm bài được ghi. ;)
Alex A.

7

Python 2, 151 140 138 byte

Việc triển khai đệ quy chậm khoảng cách Levenshtein dựa trên Wikipedia (Cảm ơn @Kenney đã cạo 11 ký tự và @ Sherlock9 cho 2 lần khác).

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

Đưa ra câu trả lời đúng cho các trường hợp kiểm tra được trình bày:

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

1
Bạn có thể tiết kiệm 3-4 byte hoặc hơn bằng cách thực hiện một cái gì đó như if !n*m:return n if n else m, và 2 cái khác bằng cách return 1+min([ f(..), f(..), f(..) - (s[..] == t[..]) ]).
Kenney

Bạn sẽ tiết kiệm được 2 byte bằng cách sử dụng f(m-1,n-1)-(s[m-1]==t[n-1])thay vì f(m-1,n-1)+(s[m-1]!=t[n-1])-1.
Sherlock9


5

JavaScript (ES6) 106 113 122

Chỉnh sửa 16 byte được lưu theo đề xuất @Neil

Là một chức năng ẩn danh.

(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

Đây là một triển khai thực hiện của thuật toán Wagner về Fischer chính xác như được mô tả trong bài viết wikipedia được liên kết, trong phần Lặp lại với hai hàng ma trận (ngay cả trong thực tế, chỉ sử dụng 1 hàng - mảng w )

Ít chơi gôn

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

Kiểm tra đoạn

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
Bạn có thể sử dụng [...[0,...t].keys()]thay thế? Lưu 2 byte nếu bạn có thể.
Neil

1
@Neil trông xấu xí nhưng ngắn hơn. Thx
edc65

1
Trên thực tế, bạn có thể lưu một byte khác, [...[,...t].keys()]làm việc quá tôi nghĩ.
Neil

Tôi đã quản lý để loại bỏ một byte khác bằng cách sử dụng [...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 tuyệt vời, cảm ơn một lần nữa!
edc65

4

Python 2, 118 byte

Một giải pháp của giải pháp này , nhưng nó không giống như Willem đã hoạt động được một năm, vì vậy tôi sẽ phải tự đăng nó:

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

Hãy thử trên repl.it

Lấy hai chuỗi và xuất khoảng cách đến STDOUT( được cho phép bởi meta ). Hãy bình luận đề xuất, tôi chắc chắn rằng điều này có thể được chơi golf hơn nữa.


Có cần thiết phải bọc mọi thứ trong một chức năng? Bạn có thể sử dụng hai input()s hoặc một input().split()?
Sherlock9

@ Sherlock9 Tôi đã thử điều đó, nhưng nó tốn thêm 1 byte theo như tôi có thể nói
FlipTack

Phải, tôi quên rằng bạn cần xác định stở đâu đó trong mã. Đừng bận tâm. Làm tốt lắm: D
Sherlock9

Tôi không chắc tại sao Willem sử dụng m or n. Bạn có thể thay thế nó bằng m+n.
Arnauld

3

Tự động , 333 byte

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

Mã kiểm tra mẫu:

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

sản lượng

3
1
4
27

3

k4, 66 byte

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

Một ngụ ý nhàm chán và cơ bản vô căn cứ của algo. Vd:

  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

Nghiêm túc, 86 82 78 byte

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

Bãi rác Hex:

2c232c23606b3b3b3bb03d222b6c229c4022b364293b295b5d6f71bd526975294064293b29405b
5d6f71bd5269752840294029405b5d6f71bd5269337d40293d592b6b6d229c40495269603bbb9f

Dùng thử trực tuyến

(Lưu ý rằng liên kết là một phiên bản khác vì có gì đó về trình thông dịch trực tuyến bị hỏng với phiên bản mới, ngắn hơn, mặc dù nó hoạt động tốt với trình thông dịch có thể tải xuống.)

Đó là về cách triển khai đơn giản nhất Nghiêm túc cho phép định nghĩa đệ quy. Nó rất chậm vì nó không ghi nhớ gì cả. Có lẽ phương thức dạng bảng có thể ngắn hơn (có thể bằng cách sử dụng các thanh ghi dưới dạng hàng), nhưng tôi khá hài lòng với điều này, mặc dù có bao nhiêu thiếu sót về ngôn ngữ của tôi. Cái đó có thể dùng

[]oq`<code>`Ri

như một cuộc gọi hàm hai đối số thích hợp là khá tốt.

Giải trình:

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

Tôi thích cách mã cố thoát khỏi phần tử trước :)
mınxomaτ

3

Python 3, 267 216 184 162 byte

Hàm này tính toán khoảng cách Levenshtein bằng cách sử dụng một mảng có 2 x len(word_2)+1kích thước.

Chỉnh sửa: Điều này không gần với câu trả lời Python 2 của Willem, nhưng đây là một câu trả lời được đánh gôn hơn với nhiều tinh chỉnh nhỏ ở đây và đó.

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]

Ung dung:

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

Võng mạc , 78 72 byte

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

Hãy thử trực tuyến!

Theo một cách nào đó, đây là một giải pháp regex thuần túy trong đó kết quả là số lượng vị trí mà regex khớp với nhau. Bởi vì tại sao không ...

Cảnh báo công bằng, đây là siêu không hiệu quả. Cách thức hoạt động này là nó giảm tối ưu hóa thực tế cho trình quay ngược của công cụ regex, đơn giản là bắt buộc tất cả các sắp xếp có thể, bắt đầu với càng ít thay đổi càng tốt và cho phép thêm một lần nữa cho đến khi có thể khớp chuỗi với các bổ sung, xóa và thay thế .

Đối với một giải pháp hợp lý hơn một chút, giải pháp này chỉ thực hiện khớp một lần và không có bất kỳ cái nhìn tiêu cực nào. Ở đây, kết quả là số lần chụp trong nhóm 2mà bạn có thể truy cập bằng match.Groups[2].Captures.CountC # chẳng hạn. Nó vẫn không hiệu quả khủng khiếp mặc dù.

Giải trình

Tôi đang giải thích phiên bản thứ hai ở trên, vì về mặt khái niệm thì dễ hơn một chút (vì nó chỉ là một trận đấu regex duy nhất). Đây là một phiên bản chưa được chỉnh sửa mà tôi đã đặt tên cho các nhóm (hoặc làm cho chúng không bị bắt) và thêm nhận xét. Hãy nhớ rằng các thành phần trong một cái nhìn nên được đọc từ sau ra trước, nhưng các thành phần thay thế và nhìn bên trong chúng nên được đọc từ trước ra sau. Vâng.

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

Sự khác biệt duy nhất với phiên bản 72 byte là chúng ta có thể loại bỏ nhóm dẫn đầu .+(và nhóm thứ hai ở đầu) bằng cách tìm các vị trí ở cuối mà chúng ta không có đủ <ops>và đếm tất cả các vị trí đó.


3

Haskell , 67 64 byte

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

Hãy thử trực tuyến! Ví dụ sử dụng: "turing" # "tarpit"sản lượng 4.


Giải thích (cho phiên bản 67 byte trước đó)

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

Đây là một giải pháp đệ quy. Cho hai chuỗi ef, trước tiên chúng ta so sánh các ký tự đầu tiên của chúng ab. Nếu chúng bằng nhau, thì khoảng cách Levenshtein của efgiống với khoảng cách Levenshtein của rs, phần còn lại efsau khi loại bỏ các ký tự đầu tiên. Mặt khác, hoặc ahoặc bcần phải được loại bỏ, hoặc cái này được thay thế bởi cái khác. [r#f,e#s,r#s]tính toán đệ quy Levenshtein cho ba trường hợp đó, minimumchọn trường hợp nhỏ nhất và 1được thêm vào để tính toán cho hoạt động loại bỏ hoặc thay thế cần thiết.

Nếu một trong các chuỗi trống, chúng tôi và lên dòng thứ hai. Trong trường hợp này, khoảng cách chỉ là chiều dài của chuỗi không trống hoặc tương đương với độ dài của cả hai chuỗi được nối với nhau.


1
Wow, đây là một giải pháp nghiêm túc, thực sự thanh lịch và ngắn gọn.
ggPeti

3

Python 3 , 105 94 93 byte

-11 byte bởi 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)

Phiên bản đánh gôn của việc triển khai ngắn nhất trên Wikibooks .

Hãy thử trực tuyến!


Giải pháp tốt đẹp. Các l=nhu cầu được bao gồm và tính vì hàm đệ quy. Bạn có thể kết hợp các trường hợp cơ sở vào if b>""<a else len(a+b).
xnor

Chơi đẹp với các nhà khai thác, thanx!
Movatica

2

Haskell, 136 byte

Gọi e. Bit chậm trên antidisestablishmentarianismvv

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 byte

Hãy thử nó ở đây!

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

Tôi đã thêm vào đó ngày hôm qua, nhưng đã thấy thử thách này ngày hôm nay, tức là, ngay bây giờ. Tuy nhiên, câu trả lời này là không cấu hình.

Trong phiên bản mới hơn:

~Li

mất đầu vào thứ hai ẩn.


" Mã của bạn phải là một chương trình hoặc một hàm. Nó không cần phải là một hàm được đặt tên, nhưng nó không thể là một hàm tích hợp trực tiếp tính toán khoảng cách Levenshtein . Các phần dựng sẵn khác được cho phép. "
Kevin Cruijssen

À, không thấy bạn đề cập đến việc nó không cạnh tranh .. Tốt hơn nên đặt nó trong tiêu đề hoặc thêm một chương trình / chức năng hợp lệ mà không cần dựng sẵn.
Kevin Cruijssen

2

GNU Prolog, 133 byte

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

Mất một tuple như là đối số. Ví dụ về cách sử dụng:

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

D = 4

yes

mxác định đó BAtrực tiếp hoặc với ký tự đầu tiên bị xóa. dsử dụng mnhư một chương trình con để tính toán một chỉnh sửa khoảng cách giữa các yếu tố tuple (tức là khoảng cách của một loạt các chỉnh sửa mà cải đạo một vào khác). Sau đó, llà một mẹo tiêu chuẩn để tìm mức tối thiểu d(bạn lấy một khoảng cách tùy ý, sau đó lấy một khoảng cách nhỏ hơn tùy ý, lặp lại cho đến khi bạn không thể đi nhỏ hơn).


1

Perl, 168 166 163 byte

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)

Thực hiện đệ quy. Lưu trong một file.plvà chạy như 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)


Hai triển khai khác đều dài hơn (ma trận đầy đủ: 237 byte, hai lần lặp một hàng: 187).

  • cập nhật 166 : bỏ qua ()trong cuộc gọi l.
  • cập nhật 163 : loại bỏ returnbằng cách lạm dụng dotrong trinary.


0

C, 192 byte

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

Chi tiết

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

dễ đọc hơn:

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 byte

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

Tôi đã kết thúc việc này để giải quyết những thách thức khác liên quan đến LD.

Mã giải thích với ý kiến.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.