算法思路汇总:40.组合总和Ⅱ

133 阅读1分钟

40.组合总和Ⅱ

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。

难度:mid 来源:力扣(LeetCode)

题目:

给定一个候选人编号的集合 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. 1 <= candidates.length <= 100
  2. 1 <= candidates[i] <= 50
  3. 1 <= target <= 30

思路:

该题中的思路与lc39相同,但是根据题目可知,本题需要进行去重操作(解集不能包含重复的组合),这也是这题目中的难点。可以使用map或者set等.但是非常容易超时,比如我使用的List中的contains函数操作:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    int tt  = 0;
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        int len  = candidates.length;
        Arrays.sort(candidates); //[1,1,2,5,6,7,10]
        combina(candidates,len,target,0);
        return res;
    }
    void combina(int[] candidates,int len,int target,int index){
        if(target < 0) return;
        List<Integer> e = new ArrayList<>(path);
        if(res.contains(e)) return;
        if(target == 0){
            res.add(e);
            return;
        }
        for(int i = index; i < len; i++){
            path.add(candidates[i]);
            combina(candidates,len,target-candidates[i],i+1);
            path.removeLast();
​
        }
    }
}

直接就超了:

172 / 175 个通过测试用例
状态:超出时间限制
提交时间:1 小时前
最后执行的输入:
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
30

既然不能在结果集中去重,那么只能在递归的过程中。如何去重呢?代码如下:

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

解释其去重原理:引自于leetcode中的Allen大佬

但是个人看完还是不太明白,为什么i会出现比index大的情况?

于是只能手动debug一下:

这里是个人的理解视频,有什么问题欢迎指正。

debug调试

完整代码

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        int len  = candidates.length;
        Arrays.sort(candidates); //[1,1,2,5,6,7,10]
        combina(candidates,len,target,0);
        return res;
    }
    void combina(int[] candidates,int len,int target,int index){
        if(target < 0) return;
        List<Integer> e = new ArrayList<>(path);
        if(target == 0){
            res.add(e);
            return;
        }
        for(int i = index; i < len; i++){
            if(i>index&&candidates[i]==candidates[i-1])
            {
                continue;
            }else{
                path.add(candidates[i]);
                combina(candidates,len,target-candidates[i],i+1);
                path.removeLast();
            }
            
        }
    }
}

调试代码:

package com.lc;
​
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
​
public class lc40 {
    static List<List<Integer>> res = new ArrayList<>();
    static LinkedList<Integer> path = new LinkedList<>();
    public static void main(String[] args) {
        int[] candidates = new int[]{2,5,2,1,2};
        int target = 5;
        combinationSum2(candidates,target);
    }
    public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
        int len  = candidates.length;
        Arrays.sort(candidates); //[1,1,2,5,6,7,10]
        combina(candidates,len,target,0);
        return res;
    }
    static void combina(int[] candidates, int len, int target, int index){
        if(target < 0) return;
        List<Integer> e = new ArrayList<>(path);
        if(res.contains(e)) return;
        if(target == 0){
            res.add(e);
            return;
        }
        for(int i = index; i < len; i++){
            if(i>index&&candidates[i]==candidates[i-1])
            {
                continue;
            }else{
                path.add(candidates[i]);
                combina(candidates,len,target-candidates[i],i+1);
                path.removeLast();
            }
​
        }
    }
}