package com.heu.wsq.leetcode.huisu;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 90. 子集 II
* @author wsq
* @date 2021/3/31
* 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
* 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
*
* 示例 1:
* 输入:nums = [1,2,2]
* 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
*
* 示例 2:
* 输入:nums = [0]
* 输出:[[],[0]]
*
* 链接:https://leetcode-cn.com/problems/subsets-ii
*/
public class SubsetsWithDup {
// 存储子集的集合
List<List<Integer>> ans = new ArrayList<>();
// 存储当前路径
List<Integer> path = new ArrayList<>();
/**
* 题目要求,不能有重复的子集
* 因此将原数组排序后,后续出现的重复数字不能再遍历,因为它必定是之前与之相等数字的子集
* 所谓去重,其实就是使用过的元素不能重复选取
* @param nums
* @return
*/
public List<List<Integer>> subsetsWithDup(int[] nums) {
int n = nums.length;
if(n == 0){
return ans;
}
// 排序数组, 从小到大排序
Arrays.sort(nums);
// visited保存那个元素在当前路径中被使用
boolean[] visited = new boolean[n];
// 回溯
backtrace(nums, visited, 0, n);
return ans;
}
private void backtrace(int[] nums, boolean[] visited, int start, int end){
// 将当前路径加入ans
ans.add(new ArrayList<>(path));
// 由start节点开始回溯
for(int i = start; i < end; i++){
if(i > 0 && nums[i] == nums[i-1] && !visited[i-1]){
continue;
}
// 记录当前节点被访问到了
visited[i] = true;
path.add(nums[i]);
// 进行回溯
backtrace(nums, visited, i+1, end);
// 还原回溯前的状态
visited[i] = false;
path.remove(path.size() - 1);
}
}
}
}