##### 78. Subsets 求不含重复数字的数组的子集
Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: nums = [1,2,3]
Output:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
###### 方法一:DFS
使用深度遍历,首先我们有一个能返回所有子集的ArrayList res, 和一个临时变量ArrayList tmp, 当tmp满足一定条件的时候,往res里面添加结果,注意一开始添加的是空子集。深度遍历的重点是在回溯的时候要将最后新加入的节点删去。
引入一个int pos用来记录此子集的起点在哪,比如当pos = 1的时候就是从第二个元素往后循环添加元素(0 base),每次当此层用了第i个元素,那么下一层需要传入下一个元素的位置i+1 除此之外,当循环结束要返回上一层dfs的时候我们需要把这一层刚添加元素删去。
比如输入集合为[1,2,3]应当是这么运行,
[]
[1]
[1,2]
[1,2,3] //最底层子循环到头返回删去3,上一层的子循环也到头删去2
//而此时,这一层循环刚到2,删去后还可以添加一个3
[1,3] //删除3,删除1
[2]
[2,3] //删除3,删除2
[3]
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums==null || nums.length==0)
return res;
List<Integer> temp = new ArrayList<Integer>();
res.add(temp);//加入空子集
Arrays.sort(nums);//先排序,可以保证升序输出,虽然本体没有要求,可以去掉这句,不过下一道题必须排序,因为要去除重复
dfs(nums, 0, temp, res);
return res;
}
private void dfs(int[] nums, int pos, List<Integer> temp, List<List<Integer>> res){
for(int i=pos;i<nums.length;i++){
temp.add(nums[i]);
res.add(new ArrayList<Integer>(temp));//注意new一个新的list
dfs(nums,i+1,temp,res);
temp.remove(temp.size()-1);//回溯之前删节点
}
}
###### 方法二:
在每一次的子集上添加新的元素,生成新的子集。
public List<List<Integer>> subsets(int[] S) {
List<List<Integer>> res = new ArrayList<>();
res.add(new ArrayList<Integer>());//第一轮循环只有空集,所以只能添加1
Arrays.sort(S);
for(int i : S) {
List<List<Integer>> tmp = new ArrayList<>();
for(List<Integer> sub : res) {
List<Integer> a = new ArrayList<>(sub);
a.add(i);
tmp.add(a);
}
res.addAll(tmp);
System.out.println("tiis is i="+i+",tmp is"+tmp.toString());
}
return res;
}
其效果是:
tiis is i=1,tmp is[[1]]
tiis is i=2,tmp is[[2], [1, 2]]
tiis is i=3,tmp is[[3], [1, 3], [2, 3], [1, 2, 3]]
###### 方法三: 位运算
##### 90. Subset 2
Given a collection of integers that might contain duplicates, S, return all possible subsets.
Note: Elements in a subset must be in non-descending order. The solution set must not contain duplicate subsets.
For example, If S = [1,2,2], a solution is: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
分析:
这一题是上面Subset I的延伸,在这一题种,输入集合有重复的元素了,但是要求输出结果不能有重复的Set
例如,假设集合为[2,3,3],如果按照Subset I的程序不做改动,会出现什么情况呢
[]
[2]
[2,3]
[2,3,3]
[2,3] //把最后一个3删去,再把倒数第二个3删去,此时集合剩下[2],此层的循环还没完,还可以取最后一个,3,所以生成了重复的集合[2,3]
[3]
[3,3]
[3] //同理,把最后一个3删去,再把倒数第二个3删去,第一层循环还可以取最后一个数3,所以生成了重复的集合[3]
那么,我们需要做的是,在删去元素后,再取元素的时候,不要取和刚刚取过的元素相等的元素 即加上这么一条语句
while(i < num.length-1 && num[i] == num[i+1]) i++;
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums==null || nums.length==0)
return res;
ArrayList<Integer> tmp = new ArrayList<>();
Arrays.sort(nums);//注意要排序,这样才能避免重复
res.add(tmp);
dfs(nums, 0, tmp, res);
return res;
}
private void dfs(int[] nums, int pos, List<Integer> tmp, List<List<Integer>> res){
for(int i=pos;i<nums.length;i++){
tmp.add(nums[i]);
res.add(new ArrayList<>(tmp));
dfs(nums, i+1,tmp,res);
tmp.remove(tmp.size()-1);
while(i<(nums.length-1) && nums[i]==nums[i+1]) i++;//和第一题的区别
}
}
refer:https://blog.csdn.net/u011095253/article/details/9158397