题目来源:LeetCode 377. 组合总和 Ⅳ
问题抽象: 给定一个 无重复元素 的整数数组 nums(元素值 ≥1)和一个目标整数 target(≥0),要求计算所有 和为 target 的组合数量(元素可重复使用),满足以下核心需求:
-
组合规则定义:
- 组合中每个元素可从
nums中 无限次选取; - 顺序不同的序列视为不同组合(如
(1,2)和(2,1)算两种); - 组合元素和必须 严格等于
target(无小数部分)。
- 组合中每个元素可从
-
计算约束:
- 时间复杂度 O(n × target)(
n为nums长度),空间复杂度 **O(target)`; - 需用 动态规划 避免回溯法指数级开销:
- 定义
dp[i]表示和为i的组合数; - 状态转移:
dp[i] = sum(dp[i - num] for num in nums if i ≥ num); - 初始化
dp[0] = 1(空组合和为0)。
- 定义
- 时间复杂度 O(n × target)(
-
边界处理:
target=0时返回1(空组合);nums为空且target>0时返回0;- 特殊值验证:
nums=[1,2,3],target=4→ 输出7(组合:(1,1,1,1),(2,2),(1,1,2)×3,(1,3)×2,(3,1)×2);nums=[9],target=3→ 输出0(无法组合);
- 大数处理:
nums=[1],target=1000→ 输出1(仅1000个1一种组合);- 结果值可能较大(但保证在
32位整数范围内)。
-
排列特性:
- 因顺序敏感,本质是 排列问题(与顺序无关的组合总和问题区分);
- 动态规划需 先遍历和
i(1至target),内层遍历数组元素(确保顺序差异被计数)。
输入:整数数组 nums(长度 ≥0),目标整数 target(≥0)。
输出:满足条件的组合数量(整数值)。
解题思路
本题要求找出总和为 target 的元素组合个数(不同顺序视为不同组合)。这是一个典型的动态规划问题,关键点在于:
- 状态定义:
dp[i]表示组成目标数i的组合数。 - 初始化:
dp[0] = 1(组成0只有一种方式,即空组合)。 - 状态转移:对于每个目标数
i,遍历数组nums中的每个元素num,若i >= num,则dp[i] += dp[i - num]。这表示将num作为组合的最后一个元素时,组合数取决于剩余部分i - num的组合数。 - 优化:先对数组排序,内层循环中当
num > i时提前终止(因为后续元素均大于i),减少无效计算。 - 注意事项:题目保证答案在32位整数范围内,但中间状态可能溢出。由于最终结果在范围内,中间状态直接使用
int即可。
代码实现(Java版)🔥点击下载源码
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1]; // dp[i] 表示组成目标数 i 的组合数
dp[0] = 1; // 初始化:目标数为0时只有空组合一种方式
Arrays.sort(nums); // 排序数组,便于内层循环提前终止
for (int i = 1; i <= target; i++) {
for (int num : nums) {
if (num > i) break; // 提前终止:当前数已大于目标数
dp[i] += dp[i - num]; // 状态转移
}
}
return dp[target];
}
}
代码说明
- 初始化:
dp[0] = 1表示目标数为0时只有空组合一种方式。 - 排序数组:先对
nums排序,确保在内层循环中遇到大于当前目标数i的元素时提前终止,减少无效计算。 - 动态规划:
- 外层循环遍历目标数
i从1到target。 - 内层循环遍历排序后的数组元素
num:- 若
num > i,则后续元素均大于i,直接终止内层循环。 - 否则,状态转移:
dp[i] += dp[i - num]。
- 若
- 外层循环遍历目标数
- 返回值:
dp[target]即为组成目标数target的组合数。 - 复杂度:时间复杂度 O(n log n + target * n)(排序 + 动态规划),空间复杂度 O(target)。优化后的内层循环在数组元素较大时显著减少计算量。
提交详情(执行用时、内存消耗)

1025

被折叠的 条评论
为什么被折叠?



