题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
解题思路:
解法一:枚举所有的子集后(重复的子集也记录),去重
递归枚举所有的子集,因为数组中可能包含重复的元素,也就是子集会出现重复的情况,在拿到所有的子集时,对子集进行排序,然后将排序后的子集添加到set中去重。
具体算法如下:
- 初始变量:
- tem:保存nums的一个子集
- result:保存所有的子集
- 定义递归函数,process(int nums,int cur):
- 在递归函数中选择将nums[cur]加入子集中或者不加入子集中
- 递归终止的条件,如果cur >= nums.length,return
- 否则:
- tem.add(nums[cur]):将nums[cur]加入子集中
- result.add(new ArrayList<>(tem)):tem此时保存的就是一个子集,加入到result中
- process(nums,cur+1):选择下一个加入子集中的元素
- 回溯:
- tem.remove(tem.size()-1):将nums[cur]从子集中移除,也就是不选择nums[cur]
- process(nums,cur+1)
- 递归结束后,result中保存的就是所有的子集,但是因为数组中元素会出现重复的情况,需要去重,所有可以对result中每个子集排序下,然后将排序后的子集加入set中,这样,set最终保存的就是不重复的子集
AC代码:
class Solution {
static List<Integer> tem;
static Set<List<Integer>> result;
public static List<List<Integer>> subsetsWithDup(int[] nums) {
tem = new ArrayList<>();
result = new HashSet<>();
result.add(new ArrayList<>());
process(nums, 0);
Set<List<Integer>> tem = new HashSet<>();
//排序去重
result.forEach(value->{
Collections.sort(value);
tem.add(value);
});
return new ArrayList<>(tem);
}
public static void process(int[] nums, int index) {
if (index >= nums.length) {
return;
}
tem.add(nums[index]);
result.add(new ArrayList<>(tem));
process(nums, index + 1);
tem.remove(tem.size() - 1);
process(nums, index + 1);
}
}
解法二:在解法一中,递归算法,会将重复的子集也枚举出来,最后需要对得到的结果去重,效率比较低,可以直接在递归枚举过程中跳过重复的子集,提升效率。具体算法如下:
- 对于当前选择的数nums[index],如果前面有与nums[index]相同的数 nums[i] (i<index),并且nums[i] 没有选,那么就可以跳过 nums[index](不选这个元素)。
- 比如[1,4,4],是否选第一个4,
- 当选择这个4的时候,所有可以确定的子集为[ [],[1], [1,4], [4] ],
- 当不选这个4时,所有子集为[ [],[1] ]
- 当需要选择第二个4时,[1,4,4]:是否选第二个4
- 如果第一个4没有选,那么第二个4也不选,因为(第一个4不选,第2个4选),这种情况和 (第1个4选,第2个4不选)这种情况的子集相同,所以可以直接第2个4
- 如果第1个4选,那么第2个4可以选,也可以不选,选的话可以构成更长的一个子集
- 比如[1,4,4],是否选第一个4,
- 所以,可以先对nums数组进行排序,在递归过程中,对于当前选择的数nums[index],如果前面有与nums[index]相同的数 nums[i] (i<index),并且nums[i] 没有选,那么nums[index]就不用选。这样就不会包含重复的子集了
AC代码
class Solution {
static List<Integer> tem;
static Set<List<Integer>> result;
public static List<List<Integer>> subsetsWithDup(int[] nums) {
tem = new ArrayList<>();
result = new HashSet<>();
result.add(new ArrayList<>());
Arrays.sort(nums);
process(nums, 0);
return new ArrayList<>(result);
}
public static void process(int[] nums, int index) {
if (index >= nums.length) {
return;
}
//跳过这个数
if (index>0&&nums[index-1]==nums[index]&&!tem.contains(nums[index])){
process(nums,index+1);
return;
}
tem.add(nums[index]);
result.add(new ArrayList<>(tem));
process(nums, index + 1);
tem.remove(tem.size() - 1);
process(nums, index + 1);
}
}