问题描述
小U和小R有两个字符串,分别是SS和TT,现在小U需要通过对SS进行若干次操作,使其变成TT的一个前缀。操作可以是修改SS的某一个字符,或者删除SS末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让SS变成TT的前缀。
思路:
-
我们可以使用动态规划的方法来解决这个问题。
-
定义一个二维数组
dp,其中dp[i][j]表示将S的前i个字符变成T的前j个字符的前缀所需的最少操作次数。 -
对于
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。
- 如果
-
最终结果是
dp[len(S)][len(T)]。由MarsCode AI给的解释
一、动态规划的基本思想: 我们使用动态规划来解决这个问题,核心是将原问题分解为子问题,并存储子问题的解,避免重复计算。这里定义 dp[i][j] 表示将 S 的前 i 个字符变成 T 的前 j 个字符的前缀所需的最少操作次数。
二、状态转移方程的推导:
-
当
i == 0时:- 这表示
S是一个空字符串,要将其变成T的前j个字符的前缀,需要进行j次添加操作,所以dp[0][j] = j。
- 这表示
-
当
j == 0时:- 这表示
T是一个空字符串,要将S的前i个字符变成T的前缀(空字符串),需要进行i次删除操作,所以dp[i][0] = i。
- 这表示
-
当
S[i - 1] == T[j - 1]时:- 这意味着当前字符相同,不需要额外操作,所以
dp[i][j]等于dp[i - 1][j - 1]。
- 这意味着当前字符相同,不需要额外操作,所以
-
当
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 来存储中间结果。
-
初始化
dp数组,将其长度设置为n + 1,并将dp[0]初始化为 0,因为将空字符串变成空字符串需要 0 次操作。 -
对于
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(删除操作)的最小值
- 如果
-