LeetCode 组合总和 Ⅱ(40题)图解

LeetCode 组合总和 Ⅱ

@author:Jingdai
@date:2020.11.30

题目描述(40题)

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

  • 所有数字(包括目标数)都是正整数。
  • 解集不能包含重复的组合。

示例:

输入: candidates = [2,5,2,1,2], target = 5
输出: 
[
  [1,2,2],
  [5]
]

思路及代码

一开始看到这个题,想到的处理方法是:对于每个数,有两种方式处理,一个是选取,一个是不选取(有点像01背包)。对当前数处理完之后,再对下一个数进行 dfs ,直到找到结果或处理完每一个数。同时,我们可以先对整个 candidates 数组排序,排序后如果当前节点已经大于 target 了,就可以进行剪枝了,不需要再往后 dfs 了。一图胜千言,看图。

在这里插入图片描述

然后根据此思路写出如下代码。

public List<List<Integer>> combination = new LinkedList<>();

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    
    
    LinkedList<Integer> tempCombination = new LinkedList<>();
    Arrays.sort(candidates);
    dfs(candidates, target, 0, tempCombination);
    return combination;
}

public void dfs(int[] candidates, int target, int index, LinkedList<Integer> tempCombination) {
    
    

    if (target == 0) {
    
    
        combination.add(new LinkedList<Integer>(tempCombination));
        return;
    }

    if (index == candidates.length) {
    
    
        return;       
    }

    if (candidates[index] > target) {
    
    
        return;
    }

    // target >= candidate[i]

    // choose index
    tempCombination.add(candidates[index]);
    target -= candidates[index];
    dfs(candidates, target, index+1, tempCombination);
    target += candidates[index];
    tempCombination.removeLast();

    // dont choose index
    dfs(candidates, target, index+1, tempCombination);
}

看起来好像完美,但是提交的时候傻了,并过不了,因为题目要求不能有重复的解,而我们方法不能去重。那如何进行去重呢?可以选择对结果集进行去重,但是这样就比较麻烦了,所以换一个思路。

我们刚刚是对于每个数的选择和不选择进行dfs,解空间树的每一层就是对于一个数的选择和不选择。这样不好去重,我们可以换个角度,如图,每次选择一个不同的数,这样可以保证每层的数都不一样。而下层可以选择和上一层一样的数(前提还有剩余的)。解空间树的每一层是之前没有选择的且不同节点的选择情况。

在这里插入图片描述

注意,下一次的开始下标是当前下标的下一个,因为如果继续选前面的,一定会和之前的重复。比如先选 2 ,再去选 1 的分支一定会和某个先选 1 再选 2 的分支重复。通过这种方式,就很容易的去除了重复的解。剪枝的思路和之前一样,不再赘述。代码如下。

public List<List<Integer>> combination = new LinkedList<>();

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    
    
    LinkedList<Integer> tempCombination = new LinkedList<>();
    Arrays.sort(candidates);
    dfs(candidates, target, 0, tempCombination);
    return combination;
}

public void dfs(int[] candidates, int target, int begin, LinkedList<Integer> tempCombination) {
    
    

    if (target == 0) {
    
    
        combination.add(new LinkedList<>(tempCombination));
        return;
    }

    for (int i = begin; i < candidates.length; i++) {
    
    
        if (i > begin && candidates[i] == candidates[i-1]) {
    
    
            continue;
        }

        if (candidates[i] > target) {
    
    
            return;
        }

        // choose
        target -= candidates[i]; // target >= candidates[i]
        tempCombination.add(candidates[i]);
        dfs(candidates, target, i+1, tempCombination);

        // backtrack
        target += candidates[i];
        tempCombination.removeLast();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41512783/article/details/110391438
今日推荐