回溯&子集问题

421 阅读1分钟

前言

“这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

  1. NC27 集合的所有子集(中等)
  2. 90. 子集 II

集合的所有子集

描述:现在有一个没有重复元素的整数集合S,求S的所有子集
注意:
你给出的子集中的元素必须按升序排列
给出的解集中不能出现重复的元素

输入:

[1,2,3]

返回值:

[[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

思路分析: 回溯主要是3点

  1. 结束条件
  2. 当前可以做的选择
  3. 已经做出的选择

impicture_20210815_135238.png

针对这个道题目,要求有序, 因此处理前后都需要进行排序

AC 代码:

    ArrayList<ArrayList<Integer>> ans = new ArrayList<>();

    public ArrayList<ArrayList<Integer>> subsets(int[] S) {
        Arrays.sort(S);
        dfs(S, 0, new ArrayList<>());
        Collections.sort(ans, new Comparator<ArrayList<Integer>>() {
            @Override
            public int compare(ArrayList<Integer> o1, ArrayList<Integer> o2) {
                if (o1.size() != o2.size()) {
                    return o1.size() - o2.size();
                }
                int size = o1.size();
                for (int i = 0; i < size; i++) {
                    if (o1.get(i).equals(o2.get(i))) continue;
                    return o1.get(i) - o2.get(i);
                }
                return 0;
            }
        });

        return ans;
    }

    void dfs(int[] S, int index, ArrayList<Integer> temp) {
        ans.add(new ArrayList<>(temp));
        for (int i = index; i < S.length; i++) {
            temp.add(S[i]);
            dfs(S, i + 1, temp);
            temp.remove(temp.size() - 1);
        }
    }

90. 子集 II

描述: 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

思路分析: 与上面一道题目类似, 只不过给的原始数组中包含重复的元素

  1. 暴力解法,最后对结果去重
  2. 回溯 + 剪枝 同一层不可以使用重复的元素

impicture_20210815_135959.png

  1. 若前一个元素和当前元素相同,并且未被访问,则说明前一个元素已经被使用过了。则直接跳过当前元素
  2. 若前一个元素和当前元素相同,但已被访问,则说明当前元素在前一个元素的分支下,可以使用。

AC 代码:

   List<List<Integer>> ans = new ArrayList<>();
   boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if (nums == null || nums.length == 0){
            return new ArrayList<>();
        }

        Arrays.sort(nums);
        used = new boolean[nums.length];
        help(nums, 0, new ArrayList<>());
        return ans;
    }
    
    private void help(int[] nums, int startIndex, List<Integer> temp){
        ans.add(new ArrayList<>(temp));

        for (int i = startIndex; i < nums.length; i++){
            if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]){
                continue;
            }
            temp.add(nums[i]);
            used[i] = true;
            help(nums, i + 1, temp);
            temp.remove(temp.size() - 1);
            used[i] = false;
        }
    }