📌  相关文章
📜  获得给定数组的严格 LIS 所需的最小串联(1)

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

获得给定数组的严格 LIS 所需的最小串联

有一个数组,需要找到严格递增子序列(即LIS),并将其拼接起来形成一个最小的串联结果。

解题思路

这道题可以使用动态规划来解决。具体来说,我们可以定义一个dp数组,其中dp[i]表示以nums[i]作为结尾的最长递增子序列的长度。那么,对于第i个位置,我们需要判断它前面的所有位置中哪些位置的值比nums[i]小,然后找出这些位置的dp值中最大的那个,再将这个最大的dp值加一得到dp[i],即:

dp[i] = max(dp[j] + 1), 其中 0 ≤ j <i 且 nums[j] <nums[i]。

最后,我们只需要找到dp数组中的最大值,即为所求的LIS长度。

接下来的问题是如何构造最小的串联结果。我们可以在DP的同时,记录dp[i]的来源位置,即dp[j] + 1 ==dp[i]的j。这样,当我们求出dp数组的最大值时,我们就可以从该位置开始,倒序遍历dp数组,找到所有来源位置,将相应的值拼接起来,即为所求的最小的串联结果。

代码实现
def min_concat(nums):
    n = len(nums)
    dp = [1] * n
    pre = [-1] * n  # 记录dp[i]的来源位置

    for i in range(1, n):
        for j in range(i):
            if nums[j] < nums[i] and dp[j] + 1 > dp[i]:
                dp[i] = dp[j] + 1
                pre[i] = j

    max_len = max(dp)
    end = dp.index(max_len)
    ans = [nums[end]]

    while pre[end] != -1:
        ans.append(nums[pre[end]])
        end = pre[end]

    return "".join(map(str, ans[::-1]))
测试样例
assert min_concat([10, 9, 2, 5, 3, 7, 101, 18]) == '2357'
assert min_concat([1, 3, 2, 4, 5, 6, 7]) == '1234567'
assert min_concat([4, 3, 2, 1]) == '4'
assert min_concat([2, 2]) == '2'