------------------------------------------- SUBSETS 1 -------------------------------------------
一、问题描述
Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3]
,
a solution is:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
二、我的解法
参考了别人的解法。
因为要“return all possible subsets”,所以可以用DFS解(不太明白)。
难点在于如何去掉重复set,这里采用的方法是选代表。比如[1,2,3],[3,1,2]...我们选123,因为它排好序了。
递归的时候要处理极端情况。然后回溯的时候记得remove。
代码:
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
if(nums == null){
return list;
}
if(nums.length == 0){
list.add(new ArrayList<Integer>());
return list;
}
Arrays.sort(nums);
ArrayList<Integer> subset = new ArrayList<Integer>();
this.recursion(subset, nums, 0, list);
return list;
}
private void recursion(ArrayList<Integer> subset, int[] nums, int startIndex, List<List<Integer>> list){
// deep copy
list.add(new ArrayList<>(subset));
for(int i = startIndex; i < nums.length; i++){
subset.add(nums[i]);
recursion(subset, nums, i+1, list);
// !!!
subset.remove(subset.size()-1);
}
}
}
三、其他解法
全部引用自http://bangbingsyb.blogspot.com/2014/11/leetcode-subsets-i-ii.html
1. bit manipulation
“由于S[0: n-1]组成的每一个subset,可以看成是对是否包含S[i]的取舍。S[i]只有两种状态,包含在特定subset内,或不包含。所以subset的数量总共有2^n个。所以可以用0~2^n-1的二进制来表示一个subset。二进制中每个0/1表示该位置的S[i]是否包括在当前subset中。”
2. 添加数字构建subset
“起始subset集为:[]
添加S0后为:[], [S0]
添加S1后为:[], [S0], [S1], [S0, S1]
添加S2后为:[], [S0], [S1], [S0, S1], [S2],
[S0, S2], [S1, S2], [S0, S1, S2]
红色subset为每次新增的。显然规律为添加Si后,新增的subset为克隆现有的所有subset,并在它们后面都加上Si。”
------------------------------------------- SUBSETS 2 -------------------------------------------
一、问题描述
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2]
,
a solution is:
[ [2], [1], [1,2,2], [2,2], [1,2], [] ]
二、我的解法
参考了这篇笔记:http://blog.youkuaiyun.com/u011095253/article/details/9158397
和Subset 1的区别在于集合中有重复元素了。如果按照1的方法去做,[1,2,2]的结果是:
[
[],
[1],
[1, 2],
[1, 2, 2],
[1, 2] <= 回溯到subset==[1],又取了第二个2形成新的subset,就重复了
[2]
[2, 2]
[2] <= 回溯到subset==[],又取了第二个2形成新的subset,就重复了
]
所以和1的区别是,形成新subset之前加判断,是否和之前取的数字一样,如果一样就continue。
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(nums == null){
return result;
}
if(nums.length == 0){
result.add(new ArrayList<Integer>());
return result;
}
Arrays.sort(nums);
List<Integer> subset = new ArrayList<Integer>();
this.recursion(subset, nums, 0, result);
return result;
}
private void recursion(List<Integer> subset,
int[] nums,
int startIndex,
List<List<Integer>> result){
result.add(new ArrayList<Integer>(subset));
for(int i = startIndex; i < nums.length; i ++){
// here is the difference, giving up the redundant numbers
if(i > startIndex && nums[i] == nums[i-1]){
continue;
}
subset.add(nums[i]);
recursion(subset, nums, i + 1, result);
subset.remove(subset.size()-1);
}
}
}
四、反思&收获
1. deep copy VS shallow cpy VS clone
https://stackoverflow.com/questions/6182565/deep-copy-shallow-copy-clone
http://www.jianshu.com/p/8d3b4b195501