QUESTION
Given a set of distinct integers, nums, return all possible subsets.
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], [] ]
THOUGHT I
利用位操作,很好理解,当某一位为1的时候代表可以加入到集合当中去。对于数组[1,2,3],可以用一个下标0和1表示是否选择该数字,0表示未选择,1表示选中,那么每一组3个0和1的组合表示一种选择,3位共有8种选择,分别是:
000 对应[]
001 对应[3]
010 对应[2]
011 对应[2,3]
100 …
101
110
111
那么上面为1的位表示数组中该位被选中。 那么只需要遍历0到1<< length中的数,判断每一个数中有那几位为1,为1的那几位即会构成一个子集中的一个元素。
CODE
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();
for(int i = 0;i < 1 << nums.length;i++){
ArrayList<Integer> temp = new ArrayList<Integer>();
for(int j = 0;j < nums.length;j++){
if((i & (1 << j)) != 0 )
temp.add(nums[j]);
}
result.add(new ArrayList(temp));
}
return result;
}
}
RESULT
runtime complexity is O(2^n),space complexity is O(1);
SPECIAL ATTENTION
- == 还有!= 的优先级要高于&;
== has higher priority than &. You might want to wrap your operations in () to specify your own priority.
((a[0] & 1) == 0)
Similarly for all parts of the if condition.
- 把一个List加入到另一个List当中去,如果List发生变化,存入的结果也会发生变化,也就是传址引用,我们的做法是new一个新的List;
- 注意阶段性空间的初始化位置问题;
THOUGHT II
基本思路循环+dfs,生成指定元素数目(0,1,2,…array.size()个元素)的组合。
CODE
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();
ArrayList<Integer> temp = new ArrayList<Integer>();
result.add(temp);
if(nums.length == 0)
return result;
for(int i = 1;i <= nums.length;i++){
dfs(result,temp,nums,i,0);
}
return result;
}
public void dfs(ArrayList<List<Integer>> result,ArrayList<Integer> temp,int[] nums,int len,int start){
if(temp.size() == len){//边界条件
result.add(new ArrayList<Integer>(temp));
return;
}
for(int i = start;i < nums.length;i++){
temp.add(nums[i]);
dfs(result,temp,nums,len,i+1);
temp.remove(temp.size() - 1);
}
}
}
RESULT
递归类的时间复杂度不会算;
THOUGHT III 二刷
这里有一个通用的解法,适用于回溯问题A general approach to backtracking questions in Java (Subsets, Permutations, Combination Sum, Palindrome Partitioning)
CODE
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums == null || nums.length == 0)
return res;
Arrays.sort(nums);
List<Integer> tempList = new ArrayList<>();
helper(res,tempList,nums,0);
return res;
}
private void helper(List<List<Integer>> res,List<Integer> tempList,int[] nums,int start){
res.add(new ArrayList<>(tempList));
for(int i = start;i < nums.length;i++){
tempList.add(nums[i]);
helper(res,tempList,nums,i + 1);
tempList.remove(tempList.size() - 1);
}
}
}
QUESTION II
Given a collection of integers that might contain duplicates, nums, return all possible subsets.
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], [] ]
THOUGHTS
比上个解法多了一个排序,多了一个去重。这里不是很理解为什么不排序不能通过。没有要求从小到大输出啊。
CODE
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();
ArrayList<Integer> temp = new ArrayList<Integer>();
result.add(temp);
if(nums.length == 0)
return result;
Arrays.sort(nums);
for(int i = 1;i <= nums.length;i++){
dfs(result,temp,nums,i,0);
}
return result;
}
public void dfs(ArrayList<List<Integer>> result,ArrayList<Integer> temp,int[] nums,int len,int start){
if(temp.size() == len){//边界条件
result.add(new ArrayList<Integer>(temp));
return;
}
for(int i = start;i < nums.length;i++){
temp.add(nums[i]);
dfs(result,temp,nums,len,i+1);
temp.remove(temp.size() - 1);
while(i<(nums.length - 1)&&nums[i] == nums[i+1]) {
i++;
}
}
}
}
THOUGHT II
用回溯法来进行遍历,别忘了要先排序
CODE
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums == null || nums.length == 0)
return res;
Arrays.sort(nums);
List<Integer> temp = new ArrayList<>();
helper(res,temp,nums,0);
return res;
}
private void helper(List<List<Integer>> res,List<Integer> temp,int[] nums,int start){
res.add(new ArrayList<>(temp));
for(int i = start;i < nums.length;i++){
if(i > start && nums[i] == nums[i - 1])
continue;
temp.add(nums[i]);
helper(res,temp,nums,i + 1);
temp.remove(temp.size() - 1);
}
}
}