最小编辑代价

目录

算法运用场景:

题目:

输入描述:

输出描述:

示例1

输入

输出

示例2

输入

输出

示例3

输入

输出

备注:

思路分析:

优化:

样例推导:

二维矩阵:

空间压缩:

代码展示:

二维矩阵:

空间压缩:


算法运用场景:

字符串之间最小距离是非常经典的题目,运用也非常广泛

比如在搜索中,输入:“数组的输出格式” 结果中:“字符数组输出格式”,“数组的输入输出”,

结果与我们搜索的内容虽然不一样,但是字符串距离却很小(相似)

题目:

给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。

输入描述:

输出三行,第一行和第二行均为一行字符串,分别表示两个字符串str1,str2。。第三行为三个正整数,代表ic,dc和rc。(1<=ic<=10000、1<=dc<=10000、1<=rc<=10000)

输出描述:

输出一个整数,表示编辑的最小代价。

示例1

输入

abc adc 5 3 2

输出

2

示例2

输入

abc adc 5 3 100

输出

8

示例3

输入

abc abc 5 3 2

输出

0

备注:

时间复杂度O(N*M),空间复杂度O(N)。(n,m代表两个字符串长度)

思路分析:

  1. 创建一个dp数组,dp[i][j]表示str1[0...i-1]组成的子串与str2[0...j-1]组成的子串的最优解
    1. 即长度为i的str1转换成长度为j的str2所需的最小代价
  2. 初始化:
    1. 首行:str1长度为0即空串。所以str1转换成str2必须用insert,即dp[0][j] = ic * j;
    2. 首列:str2长度为0即空串。所以str1转换成str2必须用delete,即dp[i][0] = dc * j;
  3. 其余点:
    1. str1[0...i-2]转换成str2[0...j-2]的代价 加上 将str1[i-1]转换成str[j-1]
      1. 若str1[i-1] = str2[j-1] 则dp[i-1][j-1] + rc*0;(最后一个元素相等不需要replace)
      2. 若str1[i-1] != str[j-1] 则dp[i-1][j-1] +rc*1;
    2. str1[0...i-2]转换成str2[0...j-1]的代价 加上 删去str1[i-1]的代价
      1. 即dp[i-1][j] +dc;
    3. str[0...i-1]的转换成str2[0...j-2]的代价 加上 在str1的末尾添加str2[j-1]的代价
      1. 即dp[i][j-1] +ic;
    4. 在以上三种可能性中取最小值
  4. 结果:
    1. dp[n][m]即为结果

优化:

题目要求空间复杂度为O(N) ,考虑用空间压缩的技巧

每个dp都只依赖与 左边,上面,与左上。所以用一个一维数组不断更新即可以实现

样例推导:

二维矩阵:

空间压缩:

代码展示:

二维矩阵:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    private static boolean DEBUG = false;
    public static void main(String[] args)throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String str1 = reader.readLine();
        String str2 = reader.readLine();
        String[] idr = reader.readLine().split(" ");
        int ic = Integer.parseInt(idr[0]);
        int dc = Integer.parseInt(idr[1]);
        int rc = Integer.parseInt(idr[2]);
        
        int n = str1.length();
        int m = str2.length();
        int dp[][] = new int[n+1][m+1];
        
        //初始化
        for(int j=0;j<=m;j++){//首行
            dp[0][j] = j * ic; 
        }
        for(int i=0;i<=n;i++){
            dp[i][0] = i * dc;
        }
        
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int p1 = dp[i-1][j-1] + rc * (str1.charAt(i-1)==str2.charAt(j-1)?0:1);
                int p2 = dp[i-1][j] + dc;
                int p3 = dp[i][j-1] + ic;
                dp[i][j] = Math.min(p1,Math.min(p2,p3));
                if(DEBUG) System.out.print(dp[i][j] + " ");
            }
            if(DEBUG) System.out.println();
        }
        
        System.out.print(dp[n][m]);
    }
}

空间压缩:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    private static boolean DEBUG = false;
    public static void main(String[] args)throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String str1 = reader.readLine();
        String str2 = reader.readLine();
        String[] idr = reader.readLine().split(" ");
        int ic = Integer.parseInt(idr[0]);
        int dc = Integer.parseInt(idr[1]);
        int rc = Integer.parseInt(idr[2]);
        
        int n = str1.length();
        int m = str2.length();
        int dp[] = new int[m+1];
        
        //初始化
        for(int j=0;j<=m;j++){//首行
            dp[j] = j * ic; 
        }
        
        int temp = 0;
        for(int i=1;i<=n;i++){
            
            temp = dp[0];
            dp[0] = i * dc;
            if(DEBUG) System.out.print(dp[0] + " ");
            for(int j=1;j<=m;j++){
                int p1 = temp + rc * (str1.charAt(i-1)==str2.charAt(j-1)?0:1);
                temp = dp[j];
                int p2 = dp[j] + dc;
                int p3 = dp[j-1] + ic;
                dp[j] = Math.min(p1,Math.min(p2,p3));
                if(DEBUG) System.out.print(dp[j] + " ");
            }
            if(DEBUG) System.out.println();
        }
        
        System.out.print(dp[m]);
    }
}

### 最小编辑距离算法的实现与原理 #### 动态规划的核心思想 最小编辑距离算法是一种基于动态规划的经典算法,其核心在于构建一个二维矩阵 `d` 来记录两个字符串之间的转换代价。该矩阵中的每一个元素 `d[i][j]` 表示将第一个字符串的前 `i` 个字符转换为第二个字符串的前 `j` 个字符所需要的最少操作数[^1]。 #### 初始化过程 为了便于后续计算,在开始填充矩阵之前需要对边界条件进行初始化: - 当其中一个字符串为空时,另一个字符串可以通过连续插入或删除操作完匹配。因此,对于任意 `i` 和 `j`,有 `d[i][0] = i` 和 `d[0][j] = j`[^3]。 #### 填充逻辑 在遍历过程中,根据当前字符是否相等决定如何更新矩阵值: - 如果两字符相同,则无需额外操作,直接继承左上方单元格的值: \[ d[i][j] = d[i-1][j-1] \] - 若不相同,则取三种可能操作(替换、插入、删除)中代价最小的一种并加一作为新值: \[ d[i][j] = \min\{d[i-1][j], d[i][j-1], d[i-1][j-1]\} + 1 \] 最终得到的结果存储于右下角单元格 `d[m][n]` 中,其中 `m` 和 `n` 分别代表输入字符串的长度[^4]。 以下是 Python 的一种具体实现方式: ```python def edit_distance(s1, s2): m, n = len(s1), len(s2) dp = [[0]*(n+1) for _ in range(m+1)] # Initialize boundaries for i in range(0, m+1): dp[i][0] = i for j in range(0, n+1): dp[0][j] = j # Fill the matrix using dynamic programming approach for j in range(1, n+1): for i in range(1, m+1): if s1[i-1]==s2[j-1]: dp[i][j]=dp[i-1][j-1] else: dp[i][j]= min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1 ) return dp[m][n] ``` 此函数接受两个参数——待比较的字符串`s1`和`s2`,返回它们间的最小编辑距离[^5]。 #### 时间与空间复杂度分析 上述方法的时间复杂度为 O(m*n),因为我们需要访问每一对 `(i,j)` 组合;而由于创建了一个大小为`(m+1)*(n+1)`的表格用于保存中间状态,故其空间复杂度同样为O(m*n)[^3]。然而,实际应用中可通过仅保留最近两行数据的方式进一步减少内存消耗至线性级别。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值