📌  相关文章
📜  最小化要添加到给定数组的元素,使其包含另一个给定数组作为其子序列 | 2套(1)

📅  最后修改于: 2023-12-03 15:26:27.409000             🧑  作者: Mango

最小化要添加到给定数组的元素,使其包含另一个给定数组作为其子序列

问题描述

给定两个数组 AB,找到最小的数组 C,使得 AC 的子序列,且 BCA 中的顺序。

示例
  • 输入:

    A = [1,2,3,4], B = [2,3]
    

    输出:

    [1,2,3,4]
    

    解释:

    C = [1,2,3,4] 是在 A 中拼接 B 后得到的数组,且 A 是 C 的子序列,B 是 C 在 A 中的顺序。
    
  • 输入:

    A = [1,2,3,4], B = [4,1]
    

    输出:

    [4,1,2,3]
    

    解释:

    C = [4,1,2,3] 是在 A 中拼接 B 后得到的数组,且 A 是 C 的子序列,B 是 C 在 A 中的顺序。
    
解题思路

该题可以采用动态规划(DP)解决,具体思路如下:

  1. 定义状态:$dp[i][j]$ 代表 C 中从 $1$ 到 $i$ 位置的子数组中包含 $A$ 中从 $1$ 到 $j$ 位置的子序列和 $B$ 中从 $1$ 到 $k$ 位置的子序列,$k$ 为 $B$ 的某个位置。
  2. 初始化:$dp[0][0]$ 为 $0$,其余为 $+\infty$。
  3. 状态转移:根据 $dp[i-1][j-1]$,$dp[i-1][j]$ 和 $dp[i][j-1]$ 的最小值得出 $dp[i][j]$。
  4. 返回结果:$C$ 为满足 $dp[n][m]$ 达到最小值时的 $C$ 数组。
代码实现
def min_common_subsequence(A, B):
    n, m = len(A), len(B)
    # 初始化
    dp = [[float('inf')] * (m+1) for _ in range(n+1)]
    for i in range(n+1):
        dp[i][0] = 0
    # 状态转移
    for i in range(1, n+1):
        for j in range(1, m+1):
            if A[i-1] == B[j-1]:
                dp[i][j] = min(dp[i-1][j-1]+1, dp[i-1][j], dp[i][j-1])
            else:
                dp[i][j] = min(dp[i-1][j], dp[i][j-1])
    # 返回结果
    res = []
    i, j = n, m
    while i > 0 and j > 0:
        if A[i-1] == B[j-1]:
            res.append(A[i-1])
            i -= 1
            j -= 1
        elif dp[i-1][j] < dp[i][j-1]:
            i -= 1
        else:
            j -= 1
    return res[::-1]  # 将结果翻转,得到 C

# 测试样例
A = [1,2,3,4]
B = [2,3]
C = min_common_subsequence(A, B)
print(C)  # [1, 2, 3, 4]