题目
Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
我的想法
必须枚举,枚举的题可以用backtracking来做。backtracking类似于DFS,在写递归的时候可以当作在写DFS就不会绕晕
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
res.add(new ArrayList<>());
backtrack(0, new ArrayList<>(), nums, res);
return res;
}
private void backtrack(int start, List ls, int[] nums, List<List<Integer>> res){
//for循环遍历相同前缀下的不同情况比如[1,3,4]和[1,3,5]
for(int i = start; i < nums.length; i++){
ls.add(nums[i]);
backtrack(i+1, ls, nums, res); //每一次递归调用增加前缀长度比如[1,2]和[1,2,3]
List<Integer> addList = new ArrayList<>(ls);
res.add(addList);
ls.remove(ls.size()-1);
}
}
}
解答
leetcode solution 1: Backtracking
写的更加简练
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList)); //从始至终都只有一个templist,通过循环外add,把不同情况加入结果list
for(int i = start; i < nums.length; i++){ //遍历从前缀最后一位往后的情况
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1); //每次递归start+1则前缀+1
tempList.remove(tempList.size() - 1);
}
}
leetcode solution 2:
有点像BFS,但又不尽然
如果是BFS,则首先是遍历长度为1的情况[[1], [2], [3]]
,然后再是长度为2的情况,直到达到输入数组长度
和DP有一点像,但DP是把大问题逐渐分小。
这里更像是做加法,这是利用了每个事件都是独立的存在,且不在乎顺序。姑且叫其累加法
- 初始状态为一个空集
[[]]
- 加入第一个元素
1
,则变为[[], [1]]
- 加入第二个元素
2
,则[[], [1], [2], [1,2]]
- 加入第二个元素
3
,则[[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
result.add(new ArrayList<>());
for(int n : nums){
int size = result.size(); //这里必须将当前list的大小存储在循环外,
//而不能直接在循环中用i<result.size()来判断。
//否则每次加入新的元素之后size都会加大,永远退出不了循环
for(int i=0; i<size; i++){
List<Integer> subset = new ArrayList<>(result.get(i));
subset.add(n);
result.add(subset);
}
}
return result;
}
}