📌  相关文章
📜  最长子序列,每个元素中至少有一个公共数字(1)

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

最长子序列,每个元素中至少有一个公共数字

最长子序列是指在一个序列中找到一个子序列,使得这个子序列中的元素在原序列中的相对顺序和原序列中的相对顺序相同,但允许不连续。

本题需要找到最长子序列,其中每个元素都至少有一个公共数字。

思路

动态规划。

我们可以使用一个二维数组 $dp$ 来表示最长子序列的长度,其中 $dp[i][j]$ 表示考虑原序列的前 $i$ 个元素和目标子序列的前 $j$ 个元素时,最长子序列的长度。

考虑状态转移方程。

如果第 $i$ 个元素和第 $j$ 个元素相等,那么最长子序列的长度至少应该是 $dp[i-1][j-1]+1$,即将两个元素都加入子序列中。

如果不相等,那么我们需要将原序列的前 $i$ 个元素中的某些元素去掉,或者将目标子序列的前 $j$ 个元素中的某些元素去掉,使得剩下的元素都有至少一个公共数字。这可以使用类似最长公共子序列的方法来求解,即 $dp[i][j] = \max(dp[i-1][j], dp[i][j-1])$。

最终结果就是 $dp[m][n]$,其中 $m$ 和 $n$ 分别是原序列和目标子序列的长度。

实现

时间复杂度 $O(mn)$,空间复杂度 $O(mn)$。

def find_longest_subsequence(nums, target):
    m, n = len(nums), len(target)
    dp = [[0] * (n+1) for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if nums[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])
    res = ''
    i, j = m, n
    while i > 0 and j > 0:
        if nums[i-1] == target[j-1]:
            res = nums[i-1] + res
            i -= 1
            j -= 1
        elif dp[i-1][j] > dp[i][j-1]:
            i -= 1
        else:
            j -= 1
    return res
示例

假设原序列是 [2, 1, 3, 4, 5, 7, 6, 8],目标子序列是 [1, 4, 6, 8],则最长子序列是 [1, 4, 6, 8],长度为 4。

>>> nums = [2, 1, 3, 4, 5, 7, 6, 8]
>>> target = [1, 4, 6, 8]
>>> find_longest_subsequence(nums, target)
'1468'