LeetCode 40. 组合总和 II

118 阅读1分钟

40. 组合总和 II

难度 中等

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

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

注意: 解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

示例 2:

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

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

题解

这道题也是一道组合的题目,是要查找所有能组成target的组合,且不能重复,这样要求我们遇到相同的数字的时候要特殊处理一下。

例如给出的数据[1,2,2],第二第三个元素重复了,当我们枚举了一、二元素(即[1,2]),然后枚举一、三元素时(即[1,2]),这就有相同组合了。

再举个例子[1,2,2,2],当我们枚举了一、二、三元素(即[1,2,2]),然后枚举一、三、四元素时(即[1,2,2]),又出现相同组合了。

通过上面两个例子知道,当我们前面出现一个相同的元素(例如2),我们没有选择前面这个元素,此时选择当前位置的元素(2),就会出现重复的子集。因为如果选择了前一个元素;和另一种不选择前一个元素,选择当前元素;都是同样的排列。所以我们要处理这种情况,只取第一个相同的元素。

核心代码

if(i > begin && candidates[i - 1] == candidates[i]){//遇到相同的元素,直接跳过
    continue;
}

AC代码

class Solution {
    List<List<Integer>> ans = new ArrayList<List<Integer>>();//结果集
    List<Integer> list = new ArrayList<Integer>();//辅助链表
​
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);//排序,将相同的元素排列在一起
        dfs(candidates, target, 0, 0);
        return ans;
    }
​
    void dfs(int[] candidates, int target, int begin, int sum){
        if(sum == target){//选择元素加权等于terget,找到满足条件的组合
            ans.add(new ArrayList<Integer>(list));
            return;
        }
        for(int i = begin; i < candidates.length; i++){//从begin开始枚举
            if(i > begin && candidates[i - 1] == candidates[i]){//如果出现相同元素,不枚举
                continue;
            }
            int rs = sum + candidates[i];//加上当前枚举元素
            if(rs <= target){//判断枚举之后是否小于target
                list.add(candidates[i]);//加入链表
                dfs(candidates, target, i + 1, rs);//继续枚举i + 1元素
                list.remove(list.size() - 1);//删除链表
            }else{
                break;
            }
        }
    }
}