题目描述
给你一个下标从 0 开始的整数数组 nums
和一个整数 target
。
返回和为 target
的 nums
子序列中,子序列 长度的最大值。如果不存在和为 target
的子序列,返回 -1
。
子序列 指的是从原数组中删除一些或者不删除任何元素后,剩余元素保持原来的顺序构成的数组。
样例
输入:nums = [1,2,3,4,5], target = 9
输出:3
解释:总共有 3 个子序列的和为 9:[4,5],[1,3,5] 和 [2,3,4]。
最长的子序列是 [1,3,5] 和 [2,3,4]。所以答案为 3。
输入:nums = [4,1,3,2,1,5], target = 7
输出:4
解释:总共有 5 个子序列的和为 7:[4,3],[4,1,2],[4,2,1],[1,1,5] 和 [1,3,2,1]。
最长子序列为 [1,3,2,1]。所以答案为 4。
输入:nums = [1,1,5,4,5], target = 3
输出:-1
解释:无法得到和为 3 的子序列。
限制
1 <= nums.length <= 1000
1 <= nums[i] <= 1000
1 <= target <= 1000
算法
(动态规划) $O(n \cdot target)$
- 设状态 $f(i, j)$ 表示考虑了数组前 $i$ 个元素,和为 $j$ 时的长度最大的子序列。$i$ 的有效范围为 $[1, n]$,$j$ 的有效范围为 $[0, target]$。
- 初始时 $f(0, 0) = 0$,其余为负无穷。
- 对于 $f(i, j)$,可以转移 $f(i, j) = f(i - 1, j)$,表示不选择这个元素。当 $j \ge nums(i)$ 时,可以转移 $f(i, j) = \min(f(i, j), f(i - 1, j - nums(i)) + 1)$,表示选择这个元素。
- 最终答案为 $f(n, target)$。
- 可以使用逆序转移第二维,省略掉第一维的空间。
时间复杂度
- 动态规划的状态数为 $O(n \cdot target)$,转移时间为常数,故总时间复杂度为 $O(n \cdot target)$。
空间复杂度
- 空间优化后,空间复杂度为 $O(target)$。
C++ 代码
class Solution {
public:
int lengthOfLongestSubsequence(vector<int>& nums, int target) {
const int n = nums.size();
vector<int> f(target + 1, INT_MIN);
f[0] = 0;
for (int x : nums)
for (int j = target; j >= x; j--)
f[j] = max(f[j], f[j - x] + 1);
return f[target] < 0 ? -1 : f[target];
}
};