LeetCode:39. Combination Sum

在这里插入图片描述
给一组数和一个target,给出所有以这组数中元素组成该target的不同组合。

这应该是回溯法的一个比较简单的实例,但是因为之前没有写过回溯法的代码,所以在这里简单的记录以下。

有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。回溯法的优点 在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。但是,对于可以得出明显的递推公式迭代求解的问题,还是不要用回溯法,因为它花费的时间比较长。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。可以认为回溯算法一个”通用解题法“,这是由他试探性的行为决定的,就好比求一个最优解,我可能没有很好的概念知道怎么做会更快的求出这个最优解,但是我可以尝试所有的方法,先试探性的尝试每一个组合,看看到底通不通,如果不通,则折回去,由最近的一个节点继续向前尝试其他的组合,如此反复。这样所有解都出来了,在做一下比较,能求不出最优解吗?(https://blog.csdn.net/c602273091/article/details/54799621)

代码:

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> res;
        vector<int> nums;
        sort(candidates.begin(), candidates.end());
        backtrack(res, nums, candidates, target, 0);
        return res;
    }
private:
    void backtrack(vector<vector<int>> &res, vector<int> nums, const vector<int>& cans, int remain, int index) {
        if (remain < 0) return;
        else if (remain == 0) {
            res.push_back(nums);
            return;
        }
        else {
            for (int i = index; i < cans.size(); ++i) {
                nums.push_back(cans[i]);
                backtrack(res, nums, cans, remain-cans[i], i);
                nums.pop_back();
            }
        }
    }
};

对于这段代码的一些细节:
整体上代码是这样的一个行为:先将当前元素放到结果数组里面,然后再继续向下递归,递归完成了,将这个元素拿出来,换成下一个,继续类似的操作
关于为什么第二十行的递归调用的最后一个参数还是传的i?以[2,3,5]为例。如果当前往nums里放的是2,那么下一次递归调用还得从2开始往nums里面装,因为一个元素可以被使用无数次;如果当前往nums里放的是3,那么下一次往里面还得放3,而不能从2开始放,因为要防止出现重复的结果,比如[[3,5],[5,3]].想来想去,递归调用的下一轮还是得从当前元素开始算起,所以得传入i

猜你喜欢

转载自blog.csdn.net/weixin_43462819/article/details/84453076