leetcode
leetcode 2951 ~ 3000
组合总和 Ⅳ

组合总和 Ⅳ

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 22 ms, 内存: 16.3 MB


/*
 * 思路:使用Java Stream来实现与上面相同的动态规划解决方案。
 * 我们定义dp数组来存储每个总和的组合数。
 * 对于每个数num,如果i - num >= 0,那么我们可以将dp[i-num]的组合数加到dp[i]上。
 */
import java.util.Arrays;

public class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target + 1];
        dp[0] = 1;
        Arrays.stream(nums).forEach(num -> {
            for (int i = num; i <= target; i++) {
                dp[i] += dp[i - num];
            }
        });
        return dp[target];
    }
}

解释

方法:

此题解使用了动态规划(DP)的思想来解决问题。首先,题解对输入数组进行了排序,这样做可以优化后续的处理,因为一旦遍历到的数大于当前目标值,就可以停止循环,避免无用的计算。接着,题解利用递归函数 'comb' 来计算可以达到特定目标值的组合数。每当 'comb' 被调用时,如果目标值为0,意味着找到了一种有效的组合,因此返回1。否则,函数会遍历数组中的每个数,递归地调用 'comb' 函数以当前数值减去数组中的数作为新的目标,这样逐渐减小目标值,直到目标为0或无法进一步分解。此外,使用 '@cache' 装饰器来存储已计算的结果,避免重复计算,提高效率。

时间复杂度:

O(n*target)

空间复杂度:

O(target)

代码细节讲解

🦆
题解中提到,排序数组可以帮助优化处理,具体是如何实现优化的?
在题解中,数组排序的主要优化在于提高遍历效率和减少无用计算。排序后,当在递归函数中遍历到一个数字大于当前目标值(target)时,可以立即停止遍历。因为后续的数都会更大,继续遍历这些数只会得到不满足条件的组合或重复计算。这样,排序帮助减少了对不可能产生有效结果的数的无效调用,从而节省了时间和计算资源。
🦆
为什么在递归函数中,当遇到`num > target`时可以直接返回当前的答案?
在递归函数中,当遇到一个数`num`大于目标值`target`时,可以直接返回当前的答案,因为数组已经排序,所有后续的数都将大于或等于`num`。这意味着,如果`num`已经超过了`target`,那么所有接下来的数无论如何组合,都不可能使得总和恰好等于`target`。因此,继续遍历这些数只会导致不必要的计算,没有必要继续检查更大的数。这是一种剪枝操作,可以有效减少计算量和提高效率。
🦆
动态规划通常需要考虑初始化的边界条件,这里的初始条件是什么,为什么设置成这样?
在这个动态规划的问题中,初始边界条件是当目标值`target`为0时,函数应返回1。这是因为如果目标值为0,表示不需要任何数字就已经满足了目标条件(即总和为0的唯一组合是不选任何数字),这构成了一个有效的组合。这个初始条件是递归和动态规划的基础,为递归提供了一个明确的终止条件和起点。从这个基础出发,函数可以通过递归调用来构建解决更大`target`值的解决方案。

相关问题