跳至主要內容

多样本位置全对应的尝试模型

mozzie大约 5 分钟算法算法

多样本位置全对应的尝试模型

模型核心

这个模型的核心思想是:给定两个样本数据,分别对应行和列,通过计算它们在每个位置上的对应关系,逐步填充一个二维的表格(动态规划表)。在这个模型中,行样本列样本的数据项一一对应,我们根据它们之间的关系逐步计算出最优解。具体来说,这个模型通常应用于二维动态规划的问题,其中每个位置的值依赖于行和列样本的对应关系。

常见问题类型

多样本位置全对应的尝试模型通常适用于多维数据的匹配问题。常见的应用场景包括:

  • 最长公共子序列(LCS)问题:用于找出两个字符串或数组的最长公共子序列。
  • 编辑距离(Levenshtein Distance)问题:计算将一个字符串转换成另一个字符串的最小操作次数(插入、删除、替换)。
  • 二维矩阵匹配问题:比如计算两个二维矩阵之间的最优匹配或计算距离。

模型解析:最长公共子序列(LCS)问题

假设有两个字符串 XY,我们要找出它们的最长公共子序列。这个问题可以用多样本位置全对应的尝试模型来解决,具体如下:

  1. 状态定义
    • 定义一个二维数组 dp[i][j],表示字符串 X[0..i-1] 和字符串 Y[0..j-1] 的最长公共子序列的长度。
  2. 状态转移
    • 如果 X[i-1] == Y[j-1],则 dp[i][j] = dp[i-1][j-1] + 1,表示当前字符匹配,可以增加一个公共子序列的长度。
    • 如果 X[i-1] != Y[j-1],则 dp[i][j] = max(dp[i-1][j], dp[i][j-1]),表示取去掉当前字符后的两个子序列中更长的一个。
  3. 填表顺序
    • 边界条件:当 i == 0j == 0 时,dp[i][j] = 0,表示空字符串与任何字符串的公共子序列长度为0。
    • 递推过程:从 dp[1][1] 开始,逐步填充整个表格。

代码实现

public static int longestCommonSubsequence(String X, String Y) {
    int m = X.length();
    int n = Y.length();
    int[][] dp = new int[m + 1][n + 1]; // 用于存储状态

    // 填表
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (X.charAt(i - 1) == Y.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1] + 1; // 字符相同,公共子序列长度加1
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); // 字符不同,取较长的子序列
            }
        }
    }

    return dp[m][n]; // 返回两个字符串的最长公共子序列的长度
}

状态转移过程

  1. 边界条件:
    • dp[i][0] = 0dp[0][j] = 0,因为任何字符串与空字符串的最长公共子序列长度为0。
  2. 递推过程:
    • dp[1][1] 开始,根据字符是否相等,填充表格。递推的过程中,每次更新 dp[i][j]时,都要考虑两个选项:
      1. 如果当前字符相同,则 dp[i][j] = dp[i-1][j-1] + 1
      2. 如果当前字符不同,则 dp[i][j] = max(dp[i-1][j], dp[i][j-1]),即取前一个状态。

复杂度分析

  • 时间复杂度:O(m * n),其中 mn 分别是两个字符串的长度。我们需要填充一个 m * n 的二维数组。
  • 空间复杂度:O(m * n),因为我们需要一个二维数组来存储每个状态。

模型解析:编辑距离问题(Levenshtein Distance)

编辑距离问题的目标是计算将字符串 word1 转换成字符串 word2 所需的最小操作次数,操作包括插入、删除和替换。这个问题也可以使用多样本位置全对应的尝试模型来解决。

  1. 状态定义
    • 定义一个二维数组 dp[i][j],表示将字符串 word1[0..i] 转换为字符串 word2[0..j] 所需的最小编辑操作数。
  2. 状态转移
    • 如果 word1[i-1] == word2[j-1],则 dp[i][j] = dp[i-1][j-1],表示不需要任何操作。
    • 如果 word1[i-1] != word2[j-1],则:
      • 插入操作:dp[i-1][j] + 1
      • 删除操作:dp[i][j-1] + 1
      • 替换操作:dp[i-1][j-1] + 1
    • 取三者的最小值。
  3. 填表顺序
    • 边界条件:当 i == 0j == 0 时,dp[i][j] 的值就是 ij,即转换成空字符串所需的操作次数。
    • 递推过程:从 dp[1][1] 开始逐步填充整个表格。

代码实现

public int minDistance(String word1, String word2) {
    int m = word1.length();
    int n = word2.length();

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

    // dp含义字符0..i 编辑成 0..j 需要的最少操作次数
    int[][] dp = new int[m + 1][n + 1];

    // 初始化第一行和第一列
    for (int i = 0; i <= m; i++) {
        dp[i][0] = i; // 从空串到word1的i个字符,需要i次操作(删除)
    }
    for (int j = 0; j <= n; j++) {
        dp[0][j] = j; // 从空串到word2的j个字符,需要j次操作(插入)
    }

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                // 如果 i == j 说明无需操作
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                // 插入
                int p1 = dp[i - 1][j];
                // 删除
                int p2 = dp[i][j - 1];
                // 替换
                int p3 = dp[i - 1][j - 1];
                dp[i][j] = Math.min(p1, Math.min(p2, p3)) + 1;
            }
        }
    }

    return dp[m][n]; // 返回最小编辑距离
}

复杂度分析

  • 时间复杂度:O(m * n),其中 mn 是字符串的长度。我们填充一个 m * n 的二维数组。
  • 空间复杂度:O(m * n),用于存储动态规划的状态。

总结

多样本位置全对应的尝试模型是解决涉及二维数组或多维数据匹配问题的有效方法。通过构建动态规划表并填充边界和中间部分,我们可以逐步推导出最优解。常见的应用包括最长公共子序列编辑距离等问题,它们都符合这种二维状态转移的结构。

贡献者: mozzie