Sweet Snippet 之 字符串编辑距离

2024-04-12 21:08

本文主要是介绍Sweet Snippet 之 字符串编辑距离,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

字符串编辑距离的简单实现

字符串编辑距离应该是动态规划中的代表问题了:

给定两个字符串 a a a b b b,求解将 a a a 编辑 b b b 的操作步数(距离),编辑包含以下两种操作:

  • 删除某一字符
  • 增加某一字符

(这里我们不允许变更某一字符,注意一下)

求解方法则是根据子问题的结果"递推"出原问题的结果:

设字符串 a a a 的长度为 m m m, 字符串 b b b 的长度为 n n n, 我们定义问题 C ( i , j ) C(i, j) C(i,j)

C ( i , j ) C(i, j) C(i,j) : a a a 的(前缀)子串(长度为 i i i) 与 b b b 的(前缀)子串(长度为 j j j) 的字符串编辑距离.

接着就是 C ( i , j ) C(i, j) C(i,j) 的递推公式了(这里就不做细节的讲述了,不熟悉的朋友可以参考进一步的资料)

C ( i , j ) = { i , i f j = 0 j , i f i = 0 C ( i − 1 , j − 1 ) , i f a [ i ] = b [ j ] m i n ( C ( i − 1 , j ) , C ( i , j − 1 ) ) + 1 , o t h e r w i s e C(i, j) = \left\{ \begin{aligned} % & 0, & if \ i = 0\ and\ j = 0 \\ & i, & if \ j = 0 \\ & j, & if \ i = 0 \\ & C(i - 1, j - 1), & if\ a[i] = b[j] \\ & min(C(i - 1, j), C(i, j - 1)) + 1, & otherwise \end{aligned} \right. C(i,j)=i,j,C(i1,j1),min(C(i1,j),C(i,j1))+1,if j=0if i=0if a[i]=b[j]otherwise

下面简单列份实现(Lua):

-- get key from two index
function get_key(m, n)return m .. "_" .. n
endfunction edit_dist_iter(a, b, m, n)local edit_dist_buffer = {}edit_dist_buffer[get_key(0, 0)] = 0for i = 1, m doedit_dist_buffer[get_key(i, 0)] = iendfor i = 1, n doedit_dist_buffer[get_key(0, i)] = iendfor i = 1, m dofor j = 1, n dolocal ac = a:sub(i, i)local bc = b:sub(j, j)if ac == bc thenedit_dist_buffer[get_key(i, j)] = edit_dist_buffer[get_key(i - 1, j - 1)]elselocal d1 = edit_dist_buffer[get_key(i - 1, j)]local d2 = edit_dist_buffer[get_key(i, j - 1)]edit_dist_buffer[get_key(i, j)] = math.min(d1, d2) + 1endendendreturn edit_dist_buffer[get_key(m, n)]
endfunction edit_dist(a, b)return edit_dist_iter(a, b, #a, #b)
end

以上的代码使用了迭代形式,我们也可以用递归形式(来编写代码),只是递归会引起不少的重复计算,所以(工程)实现上,我们需要使用缓存来记录计算过的子问题结果(迭代版本也使用了缓存,作用上和递归版本其实也是一致的,记录的也是子问题的结果):

-- get key from two index
function get_key(m, n)return m .. "_" .. n
endfunction edit_dist_recur(a, b, m, n, buffer)if m <= 0 then-- result is trivial, do not need bufferreturn nelseif n <= 0 then-- result is trivial, do not need bufferreturn melselocal ac = a:sub(m, m)local bc = b:sub(n, n)if ac == bc thenlocal d = buffer[get_key(m - 1, n - 1)]if d thenbuffer[get_key(m, n)] = dreturn delselocal d = edit_dist_recur(a, b, m - 1, n - 1, buffer)buffer[get_key(m, n)] = dreturn dendelselocal d1 = buffer[get_key(m - 1, n)]if not d1 thend1 = edit_dist_recur(a, b, m - 1, n, buffer)endlocal d2 = buffer[get_key(m, n - 1)]if not d2 thend2 = edit_dist_recur(a, b, m, n - 1, buffer)endlocal d = math.min(d1, d2) + 1buffer[get_key(m, n)] = dreturn dendend
endfunction edit_dist(a, b)-- create bufferlocal edit_dist_buffer = {}return edit_dist_recur(a, b, #a, #b, edit_dist_buffer)
end

另外还看到一种基于编辑图(Edit Graph)的实现方式,不过思路上仍然和之前的讲述是一致的,实现上则会更复杂些,在此就不列代码了~

更多资料
  • 编辑距离 (Edit distance)
  • 编辑距离算法(Edit Distance)
  • wiki

这篇关于Sweet Snippet 之 字符串编辑距离的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898246

相关文章

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

PDF 软件如何帮助您编辑、转换和保护文件。

如何找到最好的 PDF 编辑器。 无论您是在为您的企业寻找更高效的 PDF 解决方案,还是尝试组织和编辑主文档,PDF 编辑器都可以在一个地方提供您需要的所有工具。市面上有很多 PDF 编辑器 — 在决定哪个最适合您时,请考虑这些因素。 1. 确定您的 PDF 文档软件需求。 不同的 PDF 文档软件程序可以具有不同的功能,因此在决定哪个是最适合您的 PDF 软件之前,请花点时间评估您的

C和指针:字符串

字符串、字符和字节 字符串基础 字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。 字符串长度就是字符串中字符数。 size_t strlen( char const *string ); string为指针常量(const修饰string),指向的string是常量不能修改。size_t是无符号数,定义在stddef.h。 #include <stddef.h>

PHP字符串全排列

方法一: $str = 'abc';$a =str_split($str);perm($a, 0, count($a)-1);function perm(&$ar, $k, $m) {if($k == $m){ echo join('',$ar), PHP_EOL;}else {for($i=$k; $i<=$m; $i++) {swap($ar[$k], $ar[$i]);perm($ar

PHP7扩展开发之字符串处理

前言 这次,我们来看看字符串在PHP扩展里面如何处理。 示例代码如下: <?phpfunction str_concat($prefix, $string) {$len = strlen($prefix);$substr = substr($string, 0, $len);if ($substr != $prefix) {return $prefix." ".$string;} else

十一、C语言:字符串函数

目录 一、strlen 二、strcpy 三、strcat  四、strcmp 五、strstr 六、strtok 七、strerror 一、strlen 注意:strlen()函数的返回值是size_t,两个size_t相减仍为无符号数 int main(){char arr[10] = "abc";char brr[10] = "abc123";if (strl

NC 把数字翻译成字符串

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 有一种将字母编码成数字的方式:‘a’->1, ‘b->2’, … , ‘z->26’。 现在给一串数字,返回有多少种可能的译码结果 import java.u

C语言进阶【1】--字符函数和字符串函数【1】

本章概述 字符分类函数字符转换函数strlen的使用和模拟实现strcpy的使用和模拟实现strcat的使用和模拟实现strcmp的使用和模拟实现彩蛋时刻!!! 字符分类函数 字符: 这个概念,我们在以前的文章中讲过了。我们键盘输入的信息都是字符。字符大体可以分为两类——单个字符,字符串。而单个字符又可以进行分类——字母字符,数字字符,特殊字符和不可见字符。进行思维图展示: 在日

线性代数|机器学习-P35距离矩阵和普鲁克问题

文章目录 1. 距离矩阵2. 正交普鲁克问题3. 实例说明 1. 距离矩阵 假设有三个点 x 1 , x 2 , x 3 x_1,x_2,x_3 x1​,x2​,x3​,三个点距离如下: ∣ ∣ x 1 − x 2 ∣ ∣ 2 = 1 , ∣ ∣ x 2 − x 3 ∣ ∣ 2 = 1 , ∣ ∣ x 1 − x 3 ∣ ∣ 2 = 6 \begin{equation} ||x

nyoj 685 查找字符串

当初一开始没做出来。 后来,学习过一段时间之后,在返回来做这道题,忽然发现,map类容器可以做。 PS:需要注意的是:此题如果用c++的输入输出的话,会超时。 O(time):gets()<  scanf() < cin。   附上代码: #include<stdio.h>#include<map>#include<string>#include<string.h>usin