📜  总和值不超过K的最长递增子序列(1)

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

总和值不超过K的最长递增子序列

简介

指定一个整数K,找到一个最长的递增子序列,使其总和值不超过K。

解题思路

使用动态规划(DP)的思路进行求解,使用一个一维的数组dp来保存对于0~i这i个数的最长递增子序列的长度,同时,使用一个sum来记录当前最长递增子序列的和值,当sum超过K时,需要缩短当前最长递增子序列的长度。

具体流程如下:

  1. 初始化一个长度为n的数组dp,全部赋值为1。这里的n指的是题目给出的序列的长度。
  2. 初始化sum为0。
  3. 从0到n遍历整个数组,对于每一个位置i,都从0到i-1遍历之前的所有位置j。如果nums[i] > nums[j]并且dp[j] + 1 > dp[i],则更新dp[i]dp[j] + 1,表示在之前的最长递增子序列基础上,加上当前位置可以构成更长的递增子序列。这个过程相当于求解以nums[i]结尾的最长递增子序列的长度。
  4. 每次更新dp[i]时,判断当前最长递增子序列的和是否大于K,如果大于,则需要缩短当前最长递增子序列的长度。具体做法是:从i位置倒序遍历到0,找到一个满足dp[x] == dp[i] - 1的位置x,然后将sum减去nums[x],表示从最长递增子序列中删掉了nums[x]这个数,然后将dp[i]更新为dp[x],表示从当前位置重新开始构建一个更短的递增子序列。
  5. 在遍历过程中,始终更新最大的sum值,表示当前最长递增子序列的和值。

最终的答案为dp数组中的最大值。

代码实现
def get_longest_increasing_subsequence(nums: List[int], k: int) -> int:
    n = len(nums)
    dp = [1] * n
    sums = [nums[i] for i in range(n)]
    ans = 0
    
    for i in range(n):
        for j in range(i):
            if nums[i] > nums[j] and dp[j] + 1 > dp[i]:
                dp[i] = dp[j] + 1
                sums[i] = sums[j] + nums[i]
        ans = max(ans, dp[i])
        if sums[i] > k:
            for j in range(i-1, -1, -1):
                if dp[j] == dp[i] - 1:
                    sums[i] -= nums[j]
                    dp[i] = dp[j]
                    break
    
    return ans