📅  最后修改于: 2023-12-03 14:55:21.529000             🧑  作者: Mango
给定两个数组 target
和 arr
,要求通过向 arr
中添加一些元素,使得 arr
包含 target
作为其子序列,并且添加的元素数量最小。
这是一道经典的动态规划问题。我们可以定义状态 $dp_{i,j}$ 表示让 arr[0..i]
包含 target[0..j]
的最小添加次数。则最终答案为 $dp_{n-1,m-1}$,其中 $n$ 和 $m$ 分别为 arr
和 target
的长度。
接下来,我们考虑如何转移。如果当前 arr[i]
和 target[j]
相等,则 $dp_{i,j}=dp_{i-1,j-1}$,因为不需要添加额外元素即可匹配。如果不相等,则可以考虑在 arr[i]
上添加一个元素,使得 arr[0..i-1]
包含 target[0..j]
,即 $dp_{i,j}=dp_{i-1,j}+1$。特别地,当 $j=0$ 时,对应的状态只需要判断当前 arr[i]
是否等于 target[0]
即可,也就是 $dp_{i,0}=dp_{i-1,0}+1$。
最终,我们遍历数组 arr
和 target
,计算所有状态 $dp_{i,j}$,并记录其中的最小值即可。时间复杂度为 $O(nm)$。
def minOperations(target: List[int], arr: List[int]) -> int:
m, n = len(target), len(arr)
dp = [[0] * (m + 1) for _ in range(n + 1)]
for i in range(1, n+1):
for j in range(1, m+1):
if arr[i-1] == target[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return m - dp[n][m]
代码中,我们使用 dp[i][j]
表示让 arr[0..i-1]
包含 target[0..j-1]
的最小添加次数。其中,arr
和 target
的角标都是从0开始的,这一点需要注意。