Левенштайн Відстань


39

Хоча існує багато питань редагування відстаней, таких як це , не існує простого питання, щоб написати програму, яка обчислює відстань Левенштейна.

Якась експозиція

Відстань редагування Левенштейна між двома рядками - це мінімально можлива кількість вставок, вилучень або підстановок для перетворення одного слова в інше слово. У цьому випадку кожна вставка, видалення та заміна має вартість 1.

Наприклад, відстань між rollі rollingстановить 3, оскільки видалення коштує 1, а нам потрібно видалити 3 символи. Відстань між tollта tallдорівнює 1, оскільки заміна коштує 1.

Правила

  • Вхід буде двома рядками. Ви можете припустити, що рядки мають малі літери, містять лише букви, не порожні і мають довжину не більше 100 символів.
  • Вихід буде мінімальною відстані редагування Левенштейна двох рядків, як визначено вище.
  • У вашому коді повинна бути програма або функція. Вона не повинна бути іменованою функцією, але вона не може бути вбудованою функцією, яка безпосередньо обчислює відстань Левенштейна. Інші вбудовані дозволені.
  • Це кодовий гольф, тому найкоротша відповідь виграє.

Деякі приклади

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

Відповіді:


8

Pyth, 34 байти

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

Демонстрація

Це не особливо добре в гольф, і дуже повільно. Він не може впоратися ні з якими останніми двома змінами за розумний проміжок часу.


3
Але це працює, і ось що враховує. : P
Conor O'Brien

10

Матлаб, 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)

Якщо набраний код не є тим, що ви включили, будь-ласка, додайте набраний код. Інакше я думаю, що є багато пробілів, які можна виграти в гольф.
Олексій А.

1
@AlexA. провідні пробіли та нові рядки для відступу не враховуються (і їх можна безпечно видалити). Рано це було дозволено, і ніхто не скаржився.
edc65

1
@ edc65 Мета-консенсус тепер полягає в тому, що слід надати код, як забитий.
Олексій А.

2
Тож більшість вважає за краще нечитабельну версію. Я все-таки дозволю тут прочитану версію, на випадок, якщо хтось захоче побачити, що насправді відбувається =)
помилка

2
Це звичайна практика надавати як подання в гольф (та, яка забита), так і версію, що не є гольфом, ми просто вимагаємо включити забитий. ;)
Олексій А.

7

Python 2, 151 140 138 байт

Повільна рекурсивна реалізація відстані Левенштейна на основі Вікіпедії (спасибі @Kenney за гоління 11 символів та @ Sherlock9 ще 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))

Надання правильних відповідей на представлені тестові приклади:

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[..]) ]).
Кенні

Ви б зберегли 2 байти, використовуючи f(m-1,n-1)-(s[m-1]==t[n-1])замість f(m-1,n-1)+(s[m-1]!=t[n-1])-1.
Шерлок9

Відіграли 20 символів: codegolf.stackexchange.com/a/102910/60919
FlipTack

5

JavaScript (ES6) 106 113 122

Редагуйте 16 байтів, збережених після пропозицій @Neil

Як анонімна функція.

(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

Це реалізація алгоритму Вагнера – Фішера, як описано у зв'язаній статті Вікіпедії, у розділі Ітератив із двома рядками матриць (навіть якщо насправді використовується лише 1 рядок - масив w )

Менше гольфу

(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
@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)
Ніл

@Neil чудово, ще раз дякую!
edc65

4

Python 2, 118 байт

Гольф цього рішення , але це не схоже на те, що Віллем вже рік, тому мені доведеться його самостійно опублікувати:

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

Бере два рядки і виводить відстань до STDOUT( дозволене мета ). Прокоментуйте, будь ласка, пропозиції, я впевнений, що це можна пограти далі.


Чи потрібно загорнути все у функцію? Ви можете використовувати два input()s або an input().split()?
Шерлок9

@ Sherlock9 Я спробував це, але це коштує 1 байт додатково , наскільки я можу сказати
FlipTack

Правильно, я забув, що вам потрібно визначитись sі tдесь у коді. Не звертай уваги. Гарна робота: D
Шерлок9

Я не впевнений, чому Віллем користувався 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

як правильний дзвінок функції з двома аргументами був дуже приємною знахідкою.

Пояснення:

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

3

Python 3, 267 216 184 162 байт

Ця функція обчислює відстань Левенштейна за допомогою масиву 2 x len(word_2)+1за розміром.

Редагувати: Це не наближається до відповіді Віллема Пітон-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>.))*)

Спробуйте в Інтернеті!

Певним чином це чисте рішення для регулярного виведення, де результатом є кількість позицій, з яких відповідає регулярний вираз. Бо чому б ні ...

Справедливе попередження, це дуже неефективно. Це працює таким чином, що він вивантажує фактичну оптимізацію зворотного трекера двигуна регулярного випромінювання, який просто грубо примушує всі можливі вирівнювання, починаючи з якомога менших змін і дозволяючи зробити ще одну, доки не вдасться узгодити рядки з доповненнями, видаленнями та замінами .

Для дещо розумнішого рішення це відповідає лише один раз і не має жодних негативних проблем. Тут результат - кількість захоплень у групі 2, до яких ви можете отримати доступ, наприклад, match.Groups[2].Captures.Countу C #. Це все ще жахливо неефективно.

Пояснення

Я пояснюю другу версію вище, тому що це концептуально трохи простіше (оскільки це лише одна відповідність регулярного вираження). Ось неперевершена версія, я назвав групи (або зробив їх без захоплення) та додав коментарі. Пам’ятайте, що компоненти, які знаходяться позаду, повинні читатися ззаду наперед, але альтернативи та елементи пошуку всередині них слід читати спереду та назад. Так.

.+                      # 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-байтної версії полягає в тому, що ми можемо скинути провідну .+(і другу групу на початку), знайшовши позиції в кінці, де нам не вистачає, <ops>і порахувати всі ці позиції.


3

Haskell , 67 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

Це рекурсивне рішення. З огляду на два рядки eі fми першим порівняти свої перші символи aі b. Якщо вони рівні, то Левенштейна відстань eі fє таким же , як відстань Левенштейна rі s, решту eі fпісля видалення перших символів. В іншому випадку aабо bйого потрібно видалити, або один замінити іншим. [r#f,e#s,r#s]рекурсивно обчислює Левенштейн для цих трьох випадків, minimumпідбирає найменший і 1додається для обліку необхідної операції з видалення або заміни.

Якщо одна з рядків порожня, ми переходимо на другий рядок. У цьому випадку відстань - це лише довжина не порожнього рядка або рівнозначно довжині обох рядків, з'єднаних разом.


1
Нічого собі, це серйозно гарне рішення, по-справжньому елегантне та коротке.
ggPeti

3

Python 3 , 105 94 93 байт

-11 байт по 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)

Гольф-версія найкоротшої реалізації у Wikibooks .

Спробуйте в Інтернеті!


Приємне рішення. В 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

Джольф, 4 байти

Спробуйте тут!

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

Я додав, що будував вчора, але бачив цей виклик сьогодні, тобто просто зараз. Але ця відповідь є неконкурентною.

У новій версії:

~Li

приймає неявний другий вхід.


" Ваш код повинен бути програмою або функцією. Він не повинен бути іменованою функцією, але це не може бути вбудованою функцією, яка безпосередньо обчислює відстань Левенштейна . Інші вбудовані модулі дозволені ",
Кевін Круїссен

Ах, не бачив, як ви згадали, що це неконкурентоспроможне .. Краще введіть його в назву або додайте дійсну програму / функцію без вбудованого.
Кевін Кройсейсен

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)

Рекурсивна реалізація. Збережіть у a 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)


Дві інші реалізації є обома довшими (повна матриця: 237 байт, дві однорядні ітеративні: 187).

  • оновлення 166 : опустити ()дзвінок l.
  • оновлення 163 : усунення 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]

Зрештою, я вирішив це вирішити ще одну проблему, пов’язану з ЛД.

Пояснення коду з коментарями.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.