算法分析与设计——字符串编辑距离问题

本文详细介绍了字符串编辑距离问题,包括问题描述、解析、动态规划的设计与分析,以及核心代码实现。通过动态规划求解,使得在不超过2000长度的字符串间进行插入、删除、替换操作,找到最小操作次数使两个字符串相等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、问题

给定一个源串和目标串,能够对源串进行如下操作
在任意位置上插入一个字符;
替换任意字符;
删除任意字符。
写一个程序,实现返回最小操作次数,使得对源串进行上述这些操作后等于目标串(源串和目标串的长度都小于2000)

二、解析

假设目标串为s1,源串为s2,如果把源串s2的每个字符一个个对照目标串s1进行操作拟合,若 认 为s1的第i个字符为s1[i],s2的第j个字符为s2[j],那么随着i和j的分别推移,可以把思路分成以下几种情况:

  1. 如果s1[i] == s2[j]:
    即当前遍历到的s1的字符与s2的字符相等,那么说明源串不需要进行修改就和目标串匹配了,只要直接各自找下一个字符进行比较即可,即i,j各+1向后移动;
  2. 如果s1[i] != s2[j]:
    那么有三种操作,即在源串当前位置插入和目标串一样的字符,删除源串当前的字符,或者把当前位置的字符替换成和目标串一样的字符;

可以用动态规划的思路去分析其中的子问题关系,定义dis[i][j]表示当遍历到s1的第i个字符,s2的第j个字符时,使s1前i个字符与s2前j个字符相等的最短步数。假设dis[i-1][j-1]已经是最优情况,此时,为了让dis[i][j]符合要求成为最佳情况,就需要考虑在dis[i-1][j-1]进行怎样的操作能得到dis[i][j],按照之前的分析,有四种可能性,即不变、替换、插入、删除;

不变:
即当s1[i] == s2[j]时,因为不需要进行任何操作,所以dis[i][j]= dis[i-1][j-1],直接下一步即可;
替换:当s1[i] != s2[j]时, 可以把s2当前的字符s2[j]替换成s1[i],让他们相等,此时dis[i][j]= dis[i-1][j-1]+1,即在dis[i-1][j-1]的基础上步数+1即可;

插入:
当s1[i] != s2[j]时,可以在s2当前的字符s2[j]前插入一个s1[i]字符,让原本的s2[j]后移,而插入后的s2[j]位置与s1[i]相等,这相当于在dis[i-1][j]的基础上操作了一步,因为此时s1[i]还不等于s2[j],dis[i-1][j]记录了遍历到s1[i]前一位的最佳步数,只有进行了这一步插入操作之后s2[j]才会等于s1[i],所以用的是dis[i-1][j]。所以这种情况dis[i][j]= dis[i-1][j]+1;

删除:
当s1[i] != s2[j]时,可以在s2当前的字符s2[j]删除,让原本的s2[j+1]前移到s2[j],这相当于在dis[i][j-1]的基础上操作了一步,所以这种情况dis[i][j]= dis[i][j-1]+1;

只需要取上述四步中最小的结果就能保证子问题情况最小了,其中如果s1[i]==s2[j]不操作一定是最小的,剩下三个取min即可;

所以状态转移方程如下:
在这里插入图片描述

三、设计

核心DP代码:

for (int i = 0; i <= len1;i++){
   
        for (int j = 0; j <= len2;j++){
   
            //填写初始状态
            if(i==0){
   
                dis
### 编辑距离算法的设计分析 #### 定义背景 编辑距离,也被称为Levenshtein距离,在信息论、语言学计算机科学领域是用来度量两个序列相似程度的重要指标。具体来说,编辑距离是指将一个单词 \( w_1 \) 转换为另一个单词 \( w_2 \) 所需的最少单字符编辑操作次数[^2]。 这些编辑操作包括但不限于: - 删除一个字符; - 插入一个字符; - 替换一个字符为另一个不同的字符。 #### 动态规划解法 为了有效地解决这一问题,通常采用动态规划的方法来计算最小编辑距离。该方法通过构建一张二维表格 `dp` 来记录子之间的转换成本,其中 `dp[i][j]` 表示字符串A前i个字符组成的子字符串B前j个字符组成子所需的最小编辑代价。 对于任意位置 `(i,j)` 上的状态转移方程如下所示: ```python if a[i-1] == b[j-1]: dp[i][j] = dp[i-1][j-1] else: dp[i][j] = min(dp[i-1][j], # delete from A or insert into B dp[i][j-1], # insert into A or delete from B dp[i-1][j-1]) + 1# replace character at i with j ``` 边界条件则依据特殊情况设定:当一方为空时,则另一方有多少个字符就需要多少次插入/删除操作才能匹配上对方全部内容;而两者的交集部分自然不需要任何变动即可视为相同[^1]。 最终得到的结果即位于矩阵右下角处元素值 `dp[m][n]` (m,n分别为AB各自长度),这便是所求得的整体最优解——即将整个字符串A完全转变为字符串B所需执行最低限度的操作数目[^3]。 ```python def edit_distance(a, b): m, n = len(a), len(b) # Create matrix of size (m+1)x(n+1) dp = [[0] * (n + 1) for _ in range(m + 1)] # Initialize base cases where one string is empty for i in range(1, m + 1): dp[i][0] = i for j in range(1, n + 1): dp[0][j] = j # Fill the DP table using recurrence relation for i in range(1, m + 1): for j in range(1, n + 1): cost = 0 if a[i - 1] == b[j - 1] else 1 dp[i][j] = min( dp[i - 1][j] + 1, # Deletion dp[i][j - 1] + 1, # Insertion dp[i - 1][j - 1] + cost # Substitution ) return dp[-1] print(edit_distance("intention", "execution")) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值