LeetCode 40 组合总和 II - 回溯解法

LeetCode 40 组合总和 II - 回溯解法

https://leetcode.cn/problems/combination-sum-ii/description/

思路

和 [子集2](LeetCode 90 子集 II - 回溯解法.md) 类似.

先排序, 重点在于如何去重.

举例: [0,1,1,2,3] target = 3; 对于第一个[1,2]是可以的, 但是第二个1开头就不应该加入到result中.

思路1

那么, 什么时候该跳过: 如果用candidate[i]==candate[i-1]来判断跳过, 第一个1没问题, 但是当path为[1],for循环要遍历[1,2,3]时,这里的1就被跳过了,按道理不应该跳过, 如果1后面不是2是1 [1,1,2,3]那么第二个1应该被跳过, 因此被跳过的不能是第一个数.

思路2:

取第一个1后, 接着要遍历[1,2,3]. 取第二个1后要遍历[2,3],这就重复了,所以重复是在一个for循环里, 也就是说你不可以和你兄弟相同,相同就必然会出现(组合)重复,你和你孩子相同会导致一个path中有重复元素,这是允许的, 可以设置一个变量 last初始为-1, 如果for循环取出的值等于last就应该跳过, 否则继续.

举例:

for(遍历全部){
	0: 没事 -last =0;
	第一个1: 没事 last = 1;
	第二个1: 有事 跳掉因为他们的孩子树是相同的.
}

代码

class Solution {

public:

    vector<int> path;

    vector<vector<int>> result;

    vector<int> loc_canditates;

    void sel_number(int start, int end, int sum, int target){

        if(sum==target){

            result.push_back(path);

            return;

        }

        if(sum>target) return;

        int last =-1;

        for(int i = start;i<=end;i++){

            //if(i>start&&loc_canditates[i]==loc_canditates[i-1])continue;

            if(loc_canditates[i]==last) continue;

            last = loc_canditates[i];

            path.push_back(loc_canditates[i]);

            sel_number(i+1,end,sum+loc_canditates[i],target);

            path.pop_back();

        }

    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {

        loc_canditates = candidates;

        sort(loc_canditates.begin(),loc_canditates.end());

        sel_number(0,candidates.size()-1, 0, target);

        return result;

    }

};