Loading

【力扣】组合总和3(组合的去重)

问题描述


注意,如果数组里有两个元素的值相同,那么这两个元素是可以出现在同一个组合里的:
image
但是:如果按前面的思路分析的话,会发现结果中出现很多相同的组合。
像这样:
image
这很明显是由于两个相同的1造成的,因为当前的startindex对应第一个1时,向下一层递归后,starindex定位的还是1,。
image
如果用这种方法,在录入结果时剔除重复的结果,则有可能在某些极端的样例里造成超时。
问题在于,我们在跳过多余的1时,要注意只能在同层枚举时跳过,如果在向下递归时跳过,就会忽略1,1,6这个组合,并且在跳过时只能跳过后面的重复元素,否则也得不到1,1,6
得到这样的处理方式
image
每一个循环代表一层的逐个枚举,每一个递归调用代表向下一层的深入
一定要注意哪里是水平的,哪里是垂直的。
代码如下:

class Solution {
public:
    vector<vector<int> > res;
    vector<int> path;
    void backtrace(vector<int>& candidates, int target, int startindex){
	if(accumulate(path.begin(), path.end(),0) >= target){
	//if(accumulate(path) >= target){
		if(accumulate(path.begin(), path.end(),0) == target){
			// for(int i = 0; i < res.size(); i++){
			// 	if(path == res[i]){
			// 		return ;
			// 	}
			// }
			res.push_back(path);
		}
		return ;
	}
	
	for(int i = startindex; i < candidates.size(); i++){
        if(i != startindex && (candidates[i] == candidates[i - 1])){
			//cout<<"遇到了第二个1"<<endl;
			continue;
		}
		path.push_back(candidates[i]);
//		int gap = 1;
//		while(candidates[i+gap] == candidates[i]){
//			gap++;
//		}
		backtrace(candidates, target, i + 1);
		path.pop_back();
	}
}//void 
vector<vector<int> > combinationSum2(vector<int>& candidates, int target) {
    res.clear();
	path.clear();
	sort(candidates.begin(), candidates.end());
	backtrace(candidates, target, 0);
	return res; 
}
};

再看一下代码随想录的思路:

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& used) {
        if (sum == target) {
            result.push_back(path);
            return;
        }
        for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
            // used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
            // used[i - 1] == false,说明同一树层candidates[i - 1]使用过
            // 要对同一树层使用过的元素进行跳过
            if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) {
                continue;
            }
            sum += candidates[i];
            path.push_back(candidates[i]);
            used[i] = true;
            backtracking(candidates, target, sum, i + 1, used); // 和39.组合总和的区别1,这里是i+1,每个数字在每个组合中只能使用一次
            used[i] = false;
            sum -= candidates[i];
            path.pop_back();
        }
    }

public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<bool> used(candidates.size(), false);
        path.clear();
        result.clear();
        // 首先把给candidates排序,让其相同的元素都挨在一起。
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, target, 0, 0, used);
        return result;
    }
};

思路可以说基本一样,只不过他跳过同层重复元素的处理方式不一样,用了一个used数组记录状态。

posted @ 2024-03-07 21:39  SaTsuki26681534  阅读(43)  评论(0)    收藏  举报