leetcode题解:第39题Combination Sum

https://leetcode-cn.com/problems/combination-sum/submissions/

文章目录

分析

这道题也是典型的回溯算法代表题,题目要求找到所有的解,每一个解都是由候选数组中的元素组成的,因此我们可以利用回溯算法,一次将一个元素加入到组合中,再判断组合是否是一个解。在回溯过程中还需要剪枝,剪掉不可能找到解的分支和会产生重复解的分支。

解法

最容易想到的方法,把候选数组中的元素一个个加入到组合中,然后计算组合中所有元素之和:如果大于目标数,则这个搜索分支不会找到解,剪枝掉;如果等于目标数,则这个组合作为一个解;如果小于目标数,则继续将元素加入到组合中,继续搜索。
注意,由于元素是可以无限次数重复使用的,所以dfs的每个节点都有n个分支(n即候选数组的大小)。
如何去重呢?不可能去判断一个解是否已被加入到答案中,因为数组的重复比较很麻烦。回想三数之和那道题,对组合去重的方法是:保证加入到答案中的组合里面的元素按升序排序。这个想法非常实用。我们可以在搜索到比组合中最末元素小的数时进行剪枝,从而保证加入到组合中的数字按升序排序。
回溯算法的代码如下:

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> result;
        vector<int> permut;
        sort(candidates.begin(), candidates.end());
        dfs(result, candidates, target, permut);
        return result;
    }
private:
    void dfs(vector<vector<int>>& result, const vector<int>& candidates, const int& target, vector<int>& permut) {
        int sum = 0;
        for (auto num : permut) sum += num;
        if (sum == target) result.emplace_back(permut);
        else if (sum > target) return;
        for (auto num : candidates) {
            int pre = permut.size() ? permut.back() : 0;
            if (num < pre) continue;
            permut.emplace_back(num);
            dfs(result, candidates, target, permut);
            permut.pop_back();
        }
    }
};

这个代码是可以优化的。

  • 保证组合按升序排序,可以引入一个变量start,在遍历候选数组时,从start开始遍历。
  • 判断组合是否是一个解,这里用的是加法,从而导致每次都需要计算组合中元素之和。如果用减法的话,则逐步减小目标数的值,值为0时组合为一个解;值大于0时搜索继续;值小于0时这个分支搜索不到解,并且由于候选数组已排序,之后的数字也没必要参与搜索了,全部剪枝掉。
代码
class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> result;
        vector<int> permut;
        sort(candidates.begin(), candidates.end());
        dfs(result, candidates, target, permut, 0);
        return result;
    }
private:
    void dfs(vector<vector<int>>& result, const vector<int>& candidates, const int& target, \
    	vector<int>& permut, int start) {
        if (target == 0) result.emplace_back(permut);
        for (int i = start; i < candidates.size() && target - candidates[i] >= 0; ++i) {
            permut.emplace_back(candidates[i]);
            dfs(result, candidates, target - candidates[i], permut, i);
            permut.pop_back();
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值