Embora existam muitas perguntas sobre distância de edição, como esta , não há uma pergunta simples para escrever um programa que calcule a distância de Levenshtein.
Alguma exposição
A distância de edição de Levenshtein entre duas strings é o número mínimo possível de inserções, exclusões ou substituições para converter uma palavra em outra palavra. Nesse caso, cada inserção, exclusão e substituição tem um custo de 1.
Por exemplo, a distância entre roll
e rolling
é 3, porque as exclusões custam 1 e precisamos excluir 3 caracteres. A distância entre toll
e tall
é 1, porque as substituições custam 1.
Regras
- A entrada será duas strings. Você pode assumir que as seqüências de caracteres são minúsculas, contêm apenas letras, não estão vazias e têm no máximo 100 caracteres.
- A saída será a distância mínima de edição de Levenshtein das duas seqüências, conforme definido acima.
- Seu código deve ser um programa ou uma função. Ele não precisa ser uma função nomeada, mas não pode ser uma função interna que calcula diretamente a distância de Levenshtein. Outros embutidos são permitidos.
- Isso é código de golfe, então a resposta mais curta vence.
Alguns exemplos
>>> lev("atoll", "bowl")
3
>>> lev("tar", "tarp")
1
>>> lev("turing", "tarpit")
4
>>> lev("antidisestablishmentarianism", "bulb")
27
Como sempre, se o problema não estiver claro, entre em contato. Boa sorte e bom golfe!
Catálogo
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 bytesEsta é uma implementação direta desta fórmula:
Ungolfed:
fonte
Python 2,
151140138 bytesImplementação recursiva lenta da distância de Levenshtein com base na Wikipedia (obrigado a @Kenney pelo corte de 11 caracteres e @ Sherlock9 por outros 2).
Fornecendo as respostas corretas para os casos de teste apresentados:
fonte
if !n*m:return n if n else m
, e outros 2 porreturn 1+min([ f(..), f(..), f(..) - (s[..] == t[..]) ])
.f(m-1,n-1)-(s[m-1]==t[n-1])
vez def(m-1,n-1)+(s[m-1]!=t[n-1])-1
.JavaScript (ES6) 106
113 122Edite 16 bytes salvos seguindo as sugestões @Neil
Como uma função anônima.
Esta é uma implementação em golfe do algoritmo Wagner-Fischer exatamente como descrito no artigo da Wikipedia, na seção Iterativa com duas linhas da matriz (mesmo que, de fato, apenas 1 linha seja usada - matriz w )
Menos golfe
Snippet de teste
fonte
[...[0,...t].keys()]
? Salva 2 bytes, se puder.[...[,...t].keys()]
também funciona , eu acho.[...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 bytes
Golfe dessa solução , mas não parece que Willem esteja há um ano, então terei que publicá-la eu mesmo:
Experimente repl.it
Pega duas strings e gera a distância até
STDOUT
( permitida por meta ). Por favor, comente sugestões, tenho certeza de que isso pode ser jogado ainda mais.fonte
input()
s ou uminput().split()
?s
et
em algum lugar do código. Deixa pra lá. Bom trabalho: Dm or n
. Você pode substituí-lo porm+n
.AutoIt , 333 bytes
Código de teste de amostra:
rendimentos
fonte
k4, 66 bytes
Um implemento chato e basicamente não-destruído pelo algo. Ex.:
fonte
Sério,
868278 bytesHex Dump:
Experimente Online
(Observe que o link é para uma versão diferente porque algo sobre o intérprete on-line quebra com a nova versão mais curta, mesmo que funcione bem com o intérprete para download.)
É a implementação mais direta. Seriamente permite a definição recursiva. É muito lento porque não realiza nenhuma memorização. Talvez o método tabular possa ser mais curto (talvez usando os registradores como linhas), mas estou bastante satisfeito com isso, apesar das limitações que ele contém. Aquele pode usar
como uma chamada de função adequada com dois argumentos foi uma boa descoberta.
Explicação:
fonte
Python 3,
267216184162 bytesEsta função calcula a distância de Levenshtein usando uma matriz
2 x len(word_2)+1
com tamanho.Edit: Isso não chega nem perto da resposta do Willem em Python 2, mas aqui está uma resposta mais eficiente, com muitos pequenos refinamentos aqui e ali.
Ungolfed:
fonte
Retina ,
7872 bytesExperimente online!
De certa forma, essa é uma solução de regex pura em que o resultado é o número de posições das quais o regex corresponde. Porque porque não ...
Aviso justo, isso é super ineficiente. A maneira como isso funciona é que ele transfere a otimização real para o backtracker do mecanismo regex, que simplesmente força bruta em todos os alinhamentos possíveis, começando com o mínimo de alterações possível e permitindo mais um até que seja possível combinar as strings com adições, exclusões e substituições .
Para uma solução um pouco mais sensata, este faz a correspondência apenas uma vez e não tem nenhuma busca negativa. Aqui, o resultado é o número de capturas no grupo
2
, às quais você pode acessarmatch.Groups[2].Captures.Count
em C #, por exemplo. Ainda é terrivelmente ineficiente.Explicação
Estou explicando a segunda versão acima, porque é conceitualmente um pouco mais fácil (pois é apenas uma única correspondência de regex). Aqui está uma versão não destruída que chamei os grupos (ou os fiz de não capturar) e adicionei comentários. Lembre-se de que os componentes em um lookbehind devem ser lidos de trás para a frente, mas as alternativas e os lookaheads dentro deles devem ser lidos de frente para trás. Sim.
A única diferença para a versão de 72 bytes é que podemos abandonar a liderança
.+
(e o segundo grupo no começo) encontrando posições no final em que não temos o suficiente<ops>
e contando todas essas posições.fonte
Haskell ,
6764 bytesExperimente online! Exemplo de uso:
"turing" # "tarpit"
rendimentos4
.Explicação (para a versão anterior de 67 bytes)
Esta é uma solução recursiva. Dadas duas cadeias
e
ef
, primeiro comparamos seus primeiros caracteresa
eb
. Se forem iguais, a distância de Levenshtein dee
ef
é a mesma que distância de Levenshtein der
es
, o restante dee
ef
depois de remover os primeiros caracteres. Caso contrário, uma
oub
precisa ser removido ou um é substituído pelo outro.[r#f,e#s,r#s]
calcula recursivamente o Levenshtein para esses três casos,minimum
escolhe o menor e1
é adicionado para explicar a operação de remoção ou substituição necessária.Se uma das strings estiver vazia, nós subimos na segunda linha. Nesse caso, a distância é apenas o comprimento da sequência não vazia ou, equivalentemente, o comprimento de ambas as seqüências concatenadas.
fonte
Python 3 ,
1059493 bytes-11 bytes por xnor
Versão mais curta da implementação mais curta no Wikilivros .
Experimente online!
fonte
l=
necessário incluir e contar porque a função é recursiva. Você pode combinar os casos de bases emif b>""<a else len(a+b)
.Haskell, 136 bytes
Ligue
e
. Pouco lentoantidisestablishmentarianism
etc.fonte
Jolf, 4 bytes
Experimente aqui!
Eu adicionei isso ontem, mas vi esse desafio hoje, ou seja, agora. Ainda assim, esta resposta não é competitiva.
Em uma versão mais recente:
recebe segunda entrada implícita.
fonte
GNU Prolog, 133 bytes
Toma uma tupla como argumento. Exemplo de uso:
m
especifica queB
éA
diretamente ou com seu primeiro caractere removido.d
usam
como uma sub-rotina para calcular uma distância de edição entre os elementos da tupla (ou seja, a distância de uma série de edições que converte uma na outra). Então,l
é um truque padrão para encontrar o mínimo ded
(você percorre uma distância arbitrária e, em seguida, percorre uma distância menor arbitrária, repita até não poder diminuir).fonte
Perl,
168166163 bytesImplementação recursiva. Salve em
file.pl
e execute comoperl file.pl atoll bowl
.As outras duas implementações são mais longas (matriz completa: 237 bytes,
duasiterativas de uma linha: 187).()
na chamadal
.return
abusandodo
em trinary.fonte
APL (Dyalog Classic) , 34 bytes
Experimente online!
fonte
C, 192 bytes
Detalhado
fonte
C #,
215210198mais legível:
fonte
PowerShell v3 +, 247 bytes
Acabei fazendo isso para resolver outros desafios envolvendo LDs.
Código de explicação com comentários.
fonte
JavaScript (ES6),
95 9189 bytesToma entrada como
(source)(target)
. Essencialmente, uma porta da resposta Python do @ Willem (posteriormente otimizada pelo @FlipTack ).Experimente online!
fonte