leetcode
leetcode 2451 ~ 2500
和为目标值的最长子序列的长度

和为目标值的最长子序列的长度

难度:

标签:

题目描述

You are given a 0-indexed array of integers nums, and an integer target.

Return the length of the longest subsequence of nums that sums up to target. If no such subsequence exists, return -1.

A subsequence is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.

 

Example 1:

Input: nums = [1,2,3,4,5], target = 9
Output: 3
Explanation: There are 3 subsequences with a sum equal to 9: [4,5], [1,3,5], and [2,3,4]. The longest subsequences are [1,3,5], and [2,3,4]. Hence, the answer is 3.

Example 2:

Input: nums = [4,1,3,2,1,5], target = 7
Output: 4
Explanation: There are 5 subsequences with a sum equal to 7: [4,3], [4,1,2], [4,2,1], [1,1,5], and [1,3,2,1]. The longest subsequence is [1,3,2,1]. Hence, the answer is 4.

Example 3:

Input: nums = [1,1,5,4,5], target = 3
Output: -1
Explanation: It can be shown that nums has no subsequence that sums up to 3.

 

Constraints:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000
  • 1 <= target <= 1000

代码结果

运行时间: 736 ms, 内存: 16.1 MB


import java.util.*;
import java.util.stream.Collectors;

/**
 * 思路:
 * 1. 使用回溯算法来找到所有和为target的子序列。
 * 2. 使用Stream API来处理和找到最长的子序列。
 */
public class SolutionStream {
    public int maxLengthSubsequence(int[] nums, int target) {
        List<List<Integer>> subsequences = new ArrayList<>();
        backtrack(nums, target, 0, 0, new ArrayList<>(), subsequences);
        return subsequences.stream()
                .filter(list -> list.stream().mapToInt(Integer::intValue).sum() == target)
                .mapToInt(List::size)
                .max()
                .orElse(-1);
    }

    private void backtrack(int[] nums, int target, int start, int currentSum, List<Integer> currentList, List<List<Integer>> subsequences) {
        if (currentSum == target) {
            subsequences.add(new ArrayList<>(currentList));
            return;
        }
        for (int i = start; i < nums.length; i++) {
            if (currentSum + nums[i] <= target) {
                currentList.add(nums[i]);
                backtrack(nums, target, i + 1, currentSum + nums[i], currentList, subsequences);
                currentList.remove(currentList.size() - 1);
            }
        }
    }

    public static void main(String[] args) {
        SolutionStream sol = new SolutionStream();
        int[] nums1 = {1, 2, 3, 4, 5};
        int target1 = 9;
        System.out.println(sol.maxLengthSubsequence(nums1, target1)); // 输出:3

        int[] nums2 = {4, 1, 3, 2, 1, 5};
        int target2 = 7;
        System.out.println(sol.maxLengthSubsequence(nums2, target2)); // 输出:4

        int[] nums3 = {1, 1, 5, 4, 5};
        int target3 = 3;
        System.out.println(sol.maxLengthSubsequence(nums3, target3)); // 输出:-1
    }
}

解释

方法:

该题解采用了动态规划的思路来解决问题。首先定义一个一维数组 f,其中 f[j] 表示达到和为 j 的子序列的最大长度。遍历数组 nums 中的每个数 num,然后逆向更新数组 f。对于每个 num,逆向更新从 target 到 num 的值,以防止同一个元素被重复使用。这种方式确保了每次更新都是基于之前状态的最优解。最后,如果 f[target] 是正数,则表示存在和为 target 的子序列,返回其长度;否则,返回 -1 表示不存在这样的子序列。

时间复杂度:

O(n*target)

空间复杂度:

O(target)

代码细节讲解

🦆
为什么在动态规划数组f的初始化中,除了f[0]被初始化为0外,其他的都初始化为非常小的负数(-n-1)?
在动态规划的解法中,数组f的每个元素f[j]代表构成和为j的最长子序列的长度。因此,f[0]=0表示和为0的最长子序列长度为0(即没有元素)。对于其他的f[j](j>0),初始化为一个非常小的负数(-n-1)是为了表示在没有任何元素被加入时,构成一个正数和为j是不可能的。这种初始化确保只有在找到至少一个有效的子序列时,f[j]的值才会被更新为非负数,从而避免错误地返回不存在的子序列长度。
🦆
在动态规划中为什么要逆序更新数组f,直接顺序更新有什么潜在的问题?
在动态规划中逆序更新数组f是为了确保每个元素在一轮更新中只被使用一次。如果采用顺序更新,比如从f[0]到f[target],那么在更新f[j]时可能会重复使用同一元素,因为更新较小的j值可能影响到后面的j值的更新。逆序更新从f[target]到f[num](num是当前考虑的元素)可以确保当更新f[j]时,使用到的f[j-num]还没有被这轮循环中的当前元素影响,从而正确地反映了不重复使用当前元素的情况。
🦆
在代码中,变量s用于优化遍历的边界,具体是如何起到优化作用的?
变量s在代码中用于记录在当前阶段,数组nums中所有元素的和的最大可能值,但不超过target。这样,当更新动态规划数组f时,只需要考虑从num(当前元素)到s的范围,而不是从num到target的完整范围。这个优化减少了每次内循环的迭代次数,特别是当s远小于target时,可以显著提高效率。
🦆
如果nums数组中包含负数或零,这种动态规划方法是否仍然有效?如果无效,需要如何修改策略?
如果nums数组中包含负数或零,当前的动态规划方法可能不会有效,因为它假设所有的数字都是正数,且只考虑累加和。负数的加入可能导致和减少,从而需要考虑更复杂的情况,比如和可能在增加和减少之间变化。为了处理包含负数和零的情况,可以采用更一般的动态规划方法,如使用二维数组f[i][j],其中i代表考虑到第i个元素,j代表当前的和,f[i][j]表示是否可以通过前i个元素得到和为j的子序列。这种方法考虑了更多的情况,但也更为复杂和耗费资源。

相关问题