【LeetCode-377】组合总和 Ⅳ
问题
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。
示例
nums = [1, 2, 3]
target = 4所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
因此输出为 7。
解答1:DFS
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
if (target == 0) return 1;
int res = 0;
for (int i = 0; i < nums.size(); i++) // 遍历所有可能的情况,i每次都从0开始
if (target >= nums[i])
res += combinationSum4(nums, target - nums[i]);
return res;
}
};
重点思路
这是统计成功次数的DFS问题,设当前层res = 0
,每次成功时return 1
,再将res
加起来,最后就能得到我们需要的结果。
解答2:带记忆递归
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int memo[target + 1]; memset(memo, -1, sizeof(memo));
memo[0] = 1;
return dfs(nums, target, memo);
}
private:
int dfs(vector<int>& nums, int target, int* memo) {
if (memo[target] != -1) return memo[target];
int res = 0;
for (int n : nums)
if (target >= n)
res += dfs(nums, target - n, memo);
memo[target] = res;
return res;
}
};
重点思路
由于本题对回溯的要求限制非常少:可以使用重复数字,排列可以有不同顺序。
进一步分析可以发现,我们可以从之前的状态推断现在的状态,举个例子当nums = [1, 3, 4]
,则dfs(7) = (dfs(1) + dfs(6)) + (dfs(3) + dfs(4)) + (dfs(4) + dfs(3))
(括号中为target的值),所以我们可以记忆下当前target的结果,方便后续直接调用。
解答3:动态规划
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
unsigned dp[target + 1]; memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 1; i < target + 1; i++)
for (int n : nums)
if (i - n >= 0) dp[i] += dp[i - n];
return dp[target];
}
};
重点思路
动态规划方法和带记忆递归,其实就是一个自底向上和自顶向下的区别。这里需要将dp
初始化为0,因为dp[i]
使用了+=
。dp[0]
被作为动态规划的边界条件,代表target = 0
时可行结果数要加1。