且歌且行,眉目轻盈。何妨吟啸且徐行。|

胖柚の工作室

园龄:2年1个月粉丝:2关注:15

📂力扣
🔖dp
2024-04-15 21:54阅读: 7评论: 0推荐: 0

377. 组合总和 IV

题目链接:

本题是爬楼梯的又一变式。
分析样例可知,每次选择的都可以是 nums 中的任一个数,而最后选择完毕的数之和等于 target.

可以认为我们每次从 nums 中选一个数作为往上爬的台阶数,问爬 target 个台阶有多少种方案。

因此爬楼梯那个题可以认为是本题条件下 nums=[1,2] 的一个特殊情况 ,因为每次只能爬 1 个或 2 个台阶。

实现一、记忆化搜索

定义 dfs(i) 为爬 i 个台阶的方案数。考虑最后一步爬了 x=nums[j] 个台阶,那么问题变成爬 ix 个台阶的方案数,即 dfs(ix)

所以有 dfs(i)=j=0n1dfs(inums[j])
(仅在 nums[j]i 时成立)

递归边界为 dfs(0)=1,只有当不选取任何元素时,元素之和才为 0,因此只有 1 种方案。或这样理解:爬 0 个台阶的方案数为 1。也可以这样理解:我们从 target 往下爬,刚好爬到底部(递归边界)此时就找到了一个合法的方案,返回 1

递归入口为 dfs(target),也就是答案。

爬楼梯那个题的递推表示也可以由此来推出,即 dfs(i)=dfs(i1)+dfs(i2)

class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int n = nums.size();
vector<int> memo(target + 1, -1);
function<int(int)> dfs = [&] (int i) -> int {
if (i == 0) return 1;
int &res = memo[i];
if (res != -1) return res;
res = 0;
for (auto x : nums) {
if (x <= i) res += dfs(i - x);
}
return res;
};
return dfs(target);
}
};

实现二、递推

注意这里需要开到 unsigned long long 才可以。这是因为递推会把所有状态都计算出来,包括无效状态(无法组成的和),但是记忆化搜索找到的一定是可以组成的状态。(无法组成的和 说的是 无法用于组成 target 的某些序列,比如某个序列的和是 target-100, 但没有 序列能组成 100,所以这个序列对组成和为 target 的序列没有贡献)

class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int n = nums.size();
vector<unsigned long long> f(target + 1);
f[0] = 1;
for (int i = 1; i <= target; i++) {
for (auto x : nums) {
if (x <= i) f[i] += f[i - x];
}
}
return f[target];
}
};

本文作者:胖柚の工作室

本文链接:https://www.cnblogs.com/pangyou3s/p/18136993

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   胖柚の工作室  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起