[Mdfs] lc40. 组合总和 II(dfs+经典)

1. 题目来源

链接:40. 组合总和 II

必看,必刷,dfs 经典:

2. 题目解析

前导题:

每个数可选 1 次和无限次的区别。当然组合中包含了重复元素,所以上题是个完全背包问题,而本题就是个多重背包问题。

本题就不仅需要受到 target 的限制,也要受到当前枚举数的个数的限制:

  • 故先将数组排序,让重复元素排到一起方便拿双指针来计算其数量。
  • 每次拿双指针计算当前枚举的元素的数量,再重复上题的枚举工作,加上数量限制即可。
  • 但是 dfs 的时候,不再是 u + 1,因为 u + 1 还可能是当前元素,但当前元素的所有数量都是在本层循环中来枚举的。所以下一次 dfs 待枚举的数应该是 k,是下一段的第一个元素。
  • 最后回溯恢复现场,加了几个就删除即可即可。

本题由于有数字的个数限制,本质上就是一次性将一个数的所有个数内的情况全部枚举完毕。求个数可以采用哈希表,也可以采用排序+双指针,枚举完这个数后,直接就是枚举下一个不同的数了,所以 dfs 在此的第二个参数值得注意!

同上题,不会分析,应该是指数级别的。

时间复杂度:不会分析…
空间复杂度:不会分析…

代码:

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path;
    vector<vector<int>> combinationSum2(vector<int>& c, int target) {
        sort(c.begin(), c.end());
        dfs(c, 0, target);
        return ans;
    }

    void dfs(vector<int> &c, int u, int target) {
        if (target == 0) {
            ans.push_back(path);
            return ;
        }
        if (u == c.size()) return ;

        int k = u + 1;
        while (k < c.size() && c[k] == c[u]) k ++;
        int cnt = k - u;

        for (int i = 0; c[u] * i <= target && i <= cnt; i ++ ) {
            dfs(c, k, target - c[u] * i);
            path.push_back(c[u]);
        }

        for (int i = 0; c[u] * i <= target && i <= cnt; i ++ ) {
            path.pop_back();
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值