第六篇最少前缀操作问题|豆包MarsCode AI 刷题

30 阅读3分钟

问题描述

小U和小R有两个字符串,分别是SS和TT,现在小U需要通过对SS进行若干次操作,使其变成TT的一个前缀。操作可以是修改SS的某一个字符,或者删除SS末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让SS变成TT的前缀。

思路

  1. 我们可以使用动态规划的方法来解决这个问题。

  2. 定义一个二维数组 dp,其中 dp[i][j] 表示将 S 的前 i 个字符变成 T 的前 j 个字符的前缀所需的最少操作次数。

  3. 对于 dp[i][j],我们可以考虑三种情况:

    • 如果 S[i-1] == T[j-1],则 dp[i][j] = dp[i-1][j-1]
    • 可以修改 S[i-1] 使其等于 T[j-1],则 dp[i][j] = dp[i-1][j-1] + 1
    • 可以删除 S[i-1],则 dp[i][j] = dp[i-1][j] + 1
  4. 最终结果是 dp[len(S)][len(T)]

    由MarsCode AI给的解释

一、动态规划的基本思想: 我们使用动态规划来解决这个问题,核心是将原问题分解为子问题,并存储子问题的解,避免重复计算。这里定义 dp[i][j] 表示将 S 的前 i 个字符变成 T 的前 j 个字符的前缀所需的最少操作次数。

二、状态转移方程的推导

  1. 当 i == 0 时:

    • 这表示 S 是一个空字符串,要将其变成 T 的前 j 个字符的前缀,需要进行 j 次添加操作,所以 dp[0][j] = j
  2. 当 j == 0 时:

    • 这表示 T 是一个空字符串,要将 S 的前 i 个字符变成 T 的前缀(空字符串),需要进行 i 次删除操作,所以 dp[i][0] = i
  3. 当 S[i - 1] == T[j - 1] 时:

    • 这意味着当前字符相同,不需要额外操作,所以 dp[i][j] 等于 dp[i - 1][j - 1]
  4. 当 S[i - 1]!= T[j - 1] 时:

    • 有两种操作可以考虑:

      • 修改 S 的第 i - 1 个字符,使其等于 T 的第 j - 1 个字符,此时操作次数为 dp[i - 1][j - 1] + 1
      • 删除 S 的第 i - 1 个字符,此时操作次数为 dp[i - 1][j] + 1
    • 我们取这两种操作的最小值作为 dp[i][j] 的值,即 dp[i][j] = min(dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1)

三、优化后的一维数组思路: 在优化后的代码中,我们使用一维数组 dp 来存储中间结果。

  1. 初始化 dp 数组,将其长度设置为 n + 1,并将 dp[0] 初始化为 0,因为将空字符串变成空字符串需要 0 次操作。

  2. 对于 S 中的每个字符(i 从 1 到 m):

    • 首先,将当前的 dp 数组复制到 prev 数组中,因为我们需要使用上一行的结果。

    • 对于 T 中的每个字符(j 从 1 到 n):

      • 如果 S[i - 1] == T[j - 1],更新 dp[j] 为 prev[j - 1],因为不需要额外操作。
      • 否则,更新 dp[j] 为 prev[j - 1] + 1(修改操作)和 prev[j] + 1(删除操作)的最小值