最短编辑距离问题与动态规划----LeetCode 72.编辑距离

动态规划(Dynamic Programming, DP)是解决复杂问题的一个强大工具,它将问题分解成更小的子问题,并使用这些子问题的解决方案来构建整体问题的解决方案。在深入探讨最短编辑距离问题之前,让我们先理解什么是动态规划,以及如何通过动态规划的视角来看待这个问题。

原题链接:72. 编辑距离 - 力扣(LeetCode)

动态规划分析

动态规划的核心

动态规划通常用于求解最优化问题。其核心思想包括两个主要部分:

  1. **最优子结构:**问题的最优解包含其子问题的最优解。这意味着我们可以通过合并子问题的最优解来构造整个问题的最优解。

  2. **重叠子问题:**在解决问题的过程中,问题被分解成若干个子问题,其中很多子问题是重复的。

最短编辑距离的动态规划解法

在最短编辑距离问题中,我们要将一个字符串word1转换成另一个字符串word2,并且我们希望所需的操作次数尽可能少。这里的操作包括插入、删除和替换字符。

集合定义

在这个问题中,我们定义f[i][j]word1的前i个字符转换到word2的前j个字符所需的最少操作次数。这个定义本身就隐含了一个最优子结构的性质,即要得到f[i][j]的值,我们可以依赖于f[i-1][j]f[i][j-1]f[i-1][j-1]的值,这些都是更小的子问题。

属性

在这个场景下,我们关注的属性是最小值(min),因为我们要找的是最少的操作次数。

转移方程

为了构建f[i][j],我们考虑以下三种可能的最后一步操作:

  • 插入: 我们可以先将word1的前i个字符转换为word2的前j-1个字符,然后在末尾插入word2的第j个字符。这给我们 f[i][j-1] + 1

  • 删除: 我们可以先将word1的前i-1个字符转换为word2的前j个字符,然后删除word1的第i个字符。这给我们 f[i-1][j] + 1

  • ++替换或保持++: 如果word1[i]word2[j]相同,我们不需要任何操作,只需要保持即可。如果它们不同,我们需要将word1[i]替换为word2[j],这给我们 f[i-1][j-1] + 1(如果不同)或**f[i-1][j-1]**(如果相同)。

综上所述,转移方程可以表示为:

java 复制代码
f[i][j] = min(      f[i][j - 1] + 1, 
                    f[i - 1][j] + 1, 
                    f[i - 1][j - 1] + (word1[i] != word2[j])
          );

其中,(word1[i] != word2[j]) 是一个指示函数,word1[i]不等于word2[j]时值为1,否则为0。

实现

基于上述分析,我们可以实现动态规划解法来解决最短编辑距离问题。

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        int[][] f = new int[505][505];

        
        // 有一个字符串为空串
        if (n * m == 0) {
            return n + m;
        }

        for (int i = 1; i <= n; i++ ) {
            f[i][0] = i;
        }

        for (int i = 1; i <= m; i++ ) {
            f[0][i] = i;
        }

        for (int i = 1; i <= n; i++ ) {
            for (int j = 1; j <= m; j++ ) {
                f[i][j] = Math.min(f[i - 1][j] + 1, f[i][j - 1] + 1);
                f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + (word1.charAt(i - 1) == word2.charAt(j - 1) ? 0 : 1));
            }
        }
        return f[n][m];
    }
}
java 复制代码
import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sca = new Scanner(System.in);
        int N = 1010; // 假设字符串的最大长度
        char[] a = new char[N];
        char[] b = new char[N];
        int[][] f = new int[N][N]; // 动态规划数组

        int n = sca.nextInt(); // word1的长度
        String A = sca.next(); // word1
        int m = sca.nextInt(); // word2的长度
        String B = sca.next(); // word2

        // 初始化边界条件
        for (int i = 1; i <= n; i++ ) {
            a[i] = A.charAt(i - 1);
            f[i][0] = i;
        }
        for (int i = 1; i <= m; i++ ) {
            b[i] = B.charAt(i - 1);
            f[0][i] = i;
        }

        // 动态规划填表
        for (int i = 1; i <= n; i++ ) {
            for (int j = 1; j <= m; j++ ) {
                f[i][j] = Math.min(f[i][j - 1] + 1, f[i - 1][j] + 1);
                if (a[i] == b[j]) f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]);
                else f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1);
            }
        }

        System.out.println(f[n][m]); // 输出结果
    }
}

时间复杂度

这个解法的时间复杂度为O(nm),其中nm分别是字符串word1word2的长度。这是因为我们需要填充一个n x m的二维数组。

相关推荐
EterNity_TiMe_5 分钟前
【论文复现】(CLIP)文本也能和图像配对
python·学习·算法·性能优化·数据分析·clip
机器学习之心16 分钟前
一区北方苍鹰算法优化+创新改进Transformer!NGO-Transformer-LSTM多变量回归预测
算法·lstm·transformer·北方苍鹰算法优化·多变量回归预测·ngo-transformer
儿时可乖了19 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol20 分钟前
java基础概念37:正则表达式2-爬虫
java
yyt_cdeyyds26 分钟前
FIFO和LRU算法实现操作系统中主存管理
算法
xmh-sxh-131437 分钟前
jdk各个版本介绍
java
daiyang123...1 小时前
测试岗位应该学什么
数据结构
alphaTao1 小时前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode