Несмотря на то, что существует много вопросов о расстоянии редактирования, таких как этот , нет простого вопроса, чтобы написать программу, которая рассчитывает расстояние Левенштейна.
Некоторая экспозиция
Расстояние редактирования Левенштейна между двумя строками - это минимально возможное количество вставок, удалений или замен для преобразования одного слова в другое. В этом случае каждая вставка, удаление и замена имеют стоимость 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>
Matlab,
177163 байтаЭто прямая реализация этой формулы:
Ungolfed:
источник
Python 2,
151140138 байтМедленная рекурсивная реализация расстояния Левенштейна, основанная на Википедии (спасибо @Kenney за бритье 11 символов и @ Sherlock9 за еще 2).
Предоставление правильных ответов для представленных тестовых примеров:
источник
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])
вместоf(m-1,n-1)+(s[m-1]!=t[n-1])-1
.JavaScript (ES6) 106
113 122Изменить 16 байтов, сохраненных после предложений @Neil
Как анонимная функция.
Это сложная реализация алгоритма Вагнера – Фишера, точно такая же, как описанная в связанной статье в Википедии, в разделе Итеративный с двумя строками матрицы (даже если на самом деле используется только 1 строка - массив w )
Меньше гольфа
Тестовый фрагмент
источник
[...[0,...t].keys()]
вместо этого? Сохраняет 2 байта, если можете.[...[,...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)
Python 2, 118 байт
Гольф этого решения , но, похоже, Виллема не было в течение года, поэтому мне придется опубликовать его самому:
Попробуйте на repl.it
Принимает две строки и выводит расстояние до
STDOUT
( разрешено мета ). Пожалуйста, прокомментируйте предложения, я уверен, что это может быть в дальнейшем.источник
input()
с илиinput().split()
?s
иt
где-то в коде. Не берите в голову. Хорошая работа: Dm or n
. Вы можете заменить его наm+n
.AutoIt , 333 байта
Пример тестового кода:
доходность
источник
k4, 66 байт
Скучный и в основном ungolfed impl алгоритма. Напр .:
источник
Серьезно,
868278 байтШестнадцатеричный дамп:
Попробуйте онлайн
(Обратите внимание, что ссылка на другую версию, потому что что-то в онлайн-переводчике ломается с новой, более короткой версией, даже если она отлично работает с загружаемым интерпретатором.)
Это самая простая реализация. Серьезно допускает рекурсивное определение. Это очень медленно, потому что не запоминает вообще. Возможно, табличный метод мог бы быть короче (возможно, с помощью регистров в качестве строк), но я довольно доволен этим, несмотря на то, что в нем много недостатков, связанных с kludging-my-way-round-the-language. Что можно использовать
как правильный вызов функции с двумя аргументами был довольно приятной находкой.
Объяснение:
источник
Python 3,
267216184162 байтаЭта функция вычисляет расстояние Левенштейна, используя массив, который имеет
2 x len(word_2)+1
размер.Изменить: Это не близко к ответу Виллема на Python 2, но вот более гольф ответ с множеством небольших уточнений здесь и там.
Ungolfed:
источник
Сетчатка ,
7872 байтаПопробуйте онлайн!
В некотором смысле, это чистое решение для регулярных выражений, где результатом является количество позиций, из которых совпадает регулярное выражение. Потому что почему бы и нет ...
Честное предупреждение, это супер неэффективно. Это работает так, что он выгружает фактическую оптимизацию в механизм отслеживания движка regex, который просто перебирает все возможные выравнивания, начиная с как можно меньшего количества изменений и допуская еще одно, пока не станет возможным сопоставить строки с добавлениями, удалениями и заменами. ,
Для чуть более разумного решения, оно выполняет сопоставление только один раз и не имеет негативных последствий. Здесь результатом является количество перехватов в группе
2
, к которым вы можете получить доступmatch.Groups[2].Captures.Count
, например, в C #. Это все еще ужасно неэффективно все же.объяснение
Я объясняю вторую версию выше, потому что концептуально это немного проще (так как это всего лишь одно совпадение с регулярным выражением). Вот незагрязненная версия, я назвал группы (или сделал их не захватывающими) и добавил комментарии. Помните, что компоненты в представлении сзади должны читаться спереди назад, но альтернативы и подсказки внутри них должны читаться спереди назад. Да.
Единственное отличие от 72-байтовой версии состоит в том, что мы можем отбросить ведущую
.+
(и вторую группу в начале), найдя позиции в конце, где нам не хватает,<ops>
и сосчитать все эти позиции.источник
Haskell ,
6764 байтаПопробуйте онлайн! Пример использования:
"turing" # "tarpit"
доходность4
.Пояснение (для предыдущей 67-байтовой версии)
Это рекурсивное решение. Учитывая две строки
e
иf
, мы сначала сравниваем их первые символыa
иb
. Если они равны, то расстояние Левенштейнаe
иf
равно расстоянию Левенштейнаr
иs
, остаток отe
иf
после удаления первых символов. В противном случае либоa
либоb
необходимо удалить, либо один заменить другим.[r#f,e#s,r#s]
Рекурсивно вычисляет Левенштейна для этих трех случаев,minimum
выбирает наименьший и1
добавляется для учета необходимой операции удаления или замены.Если одна из строк пуста, мы и вверх на второй строке. В этом случае расстояние - это просто длина непустой строки или эквивалентная длина обеих строк, соединенных вместе.
источник
Python 3 ,
1059493 байта-11 байт по xnor
Гольф версия самой короткой реализации на Wikibooks .
Попробуйте онлайн!
источник
l=
должны быть включены и подсчитывали , потому что функция является рекурсивной. Вы можете объединить базовые случаи вif b>""<a else len(a+b)
.Haskell, 136 байт
Вызов
e
. Немного медленноantidisestablishmentarianism
и т. Д.источник
Джольф, 4 байта
Попробуй это здесь!
Я добавил, что встроил вчера, но видел этот вызов сегодня, то есть только сейчас. Тем не менее, этот ответ неконкурентен.
В более новой версии:
принимает неявный второй вход.
источник
GNU Prolog, 133 байта
Принимает кортеж в качестве аргумента. Пример использования:
m
указывает , чтоB
являетсяA
либо непосредственно , либо с ее первый символ удаляется.d
использование вm
качестве подпрограммы для вычисления в расстояние редактирования между элементами кортежей (т.е. расстояние от ряда изменений , которые обращенные друг в друга). Тогдаl
это стандартный трюк для нахождения минимумаd
(вы берете произвольное расстояние, затем выбираете произвольно меньшее расстояние, повторяйте, пока вы не можете уменьшиться).источник
Perl,
168166163 байтаРекурсивная реализация. Сохранить в
file.pl
и запустить какperl file.pl atoll bowl
.Две другие реализации являются более длинными (полная матрица: 237 байтов,
двеоднорядные итеративные: 187).()
при вызовеl
.return
путем злоупотребленияdo
в трине.источник
APL (Dyalog Classic) , 34 байта
Попробуйте онлайн!
источник
C 192 байта
Детальнее
источник
C #,
215210198более читабельно:
источник
PowerShell v3 +, 247 байт
Я сделал это, чтобы решить другие проблемы, связанные с LD.
Объяснение кода с комментариями.
источник
JavaScript (ES6),
95 9189 байтПринимает вход как
(source)(target)
. По сути это порт ответа @ Willem's Python (позже оптимизированный @FlipTack ).Попробуйте онлайн!
источник