39. Combination Sum这个程序为什么可以简单的通过参数i的传递就处理了重复的组合??

来源:8-5 回溯法解决组合问题的优化

慕码人1088981

2018-03-24

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


写回答

1回答

liuyubobobo

2018-03-25

在这里,combinationSum实际处理的是candidates[begin,n)的所有数据,要注意begin这个参数的用法,它影响了for循环的范围。也就是,在实际搜索的时候,一旦搜索到了一个候选数字candidates[i],后续搜索将不再考虑i以前的所有候选数字。这步操作处理了顺序问题。你可以理解成:我们的candidates的每一个数字都有一个索引,我们实际在挑选这些数字的时候,只按照索引从小到大的顺序进行挑选,用这样的方式避免顺序重复。


这个程序在初始的时候进行了排序,使得这个过程更好理解:其实就是我们最终获得的结果,一定是升序的(严格说是不降序的)。因为我们一但选定了candidates[i]在我们的结果集中,后续搜索的数字,是在candidates[i,n)的范围里,一定大于等于candidates[i]。因此,[2,1]这样的结果不会被这个逻辑得到。因为他是降序的:)


---


最后,我的建议是:如果想真正明白程序是怎么回事,用一个小的(4,5个元素),你认为可以说明问题的测试数据,仔细的debug一遍。找个纸笔跟踪一下,一步一步的看程序是怎样执行的,每步执行数据产生了怎样的变化,为什么可以产生某种效果(避开了重复元素?一类的),和自己想的哪里不一样,自己哪里想错了或者想漏了。


这个递归函数其实只有10行而已。跟踪起来没有想象的那么复杂。我的经验是,手动跟踪一下这个函数的运行过程,可能只需要半个小时而已。将让你彻底理解整个算法的运行机理,甚至是对递归方法本身产生更深刻的理解。比对着程序生看硬想一下午要有用得多。计算机是工科,一定要动手调试:)加油!

0
7
liuyubobobo
回复
慕码人1088981
嗯。如果允许candidates的元素重复使用,可以传i;如果不允许,则传i+1。我又看了一遍39号问题,这个问题是允许元素重复使用的,所以确实应该传i:)
2018-03-29
共7条回复

玩转算法面试-- Leetcode真题分门别类讲解

课程配套大量BAT面试真题,高频算法题解析,强化训练

7410 学习 · 1150 问题

查看课程