Solution 1:backtrack
妈呀,被虐了几天了,终于直接ac了一题,太tm激动了。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res=new ArrayList<>();
//加那个空的
res.add(new ArrayList<>());
//i表示先找所有长度为i的subset,i从长度1到长度nums.length
//多次使用backtrack
for(int i=1;i<=nums.length;i++){
List<Integer> list=new ArrayList<>();
backtrack(nums, i, 0, res, list, 0);
}
return res;
}
public void backtrack(int[] nums, int length,int t, List<List<Integer>> res, List<Integer> list, int start){
//如果当先长度t==目标长度,说明找到了
if(t==length){
res.add(new ArrayList<>(list));
return;
}
//由于原数组是不重复的,所以可以用contains
//每次更新start,保证只能依次往后找,不每次从头开始,防止【1,2,3】和【1,3,2】这种重复
for(int i=start;i<nums.length;i++){
if(!list.contains(nums[i])){
list.add(nums[i]);
backtrack(nums, length, t+1, res, list, i+1);
list.remove(list.size()-1);
}
}
}
}
Solution 2: 好trickey的recursive呀!
The idea is:
起始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。
p.s:
还是老问题,如果直接拿result.get(j)再处理会出问题,因为你重复得到的是一个tmp,都指向同一块引用,一个tmp改,所有res里之前加的tmp都会改。所以一定要重新new一个,像这样result.add(new ArrayList(tmp));
public List<List<Integer>> subsets2(int[] nums) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> tmp = new ArrayList<Integer>();
result.add(tmp); // add empty set
Arrays.sort(nums);
for (int i=0; i<nums.length; i++){
int n = result.size();
for(int j=0; j<n; j++){
// NOTE: must create a new tmp object, and add element to it.
tmp = new ArrayList<Integer>(result.get(j));
tmp.add(nums[i]);
result.add(new ArrayList<Integer>(tmp));
}
}
return result;
}