Approach 1(来offer经典)
1. Three levels. Each level represents one character.
2. Two branches. Either select or not select.
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
dfs(nums, 0, new ArrayList<Integer>(), ans);
return ans;
}
private void dfs(int[] nums, int index, List<Integer> path, List<List<Integer>> ans){
if(index == nums.length){
ans.add(new ArrayList<>(path));
return;
}
path.add(nums[index]);
dfs(nums, index + 1, path, ans);
path.remove(path.size() - 1);
dfs(nums, index + 1, path, ans);
}
}
Approach 2(Another kind of DFS)
这也是另一种常见的DFS思路,依然根据孙老师传授的要诀来解释这种思路:
1. 每一层代表什么含义
长度相等的所有可能性
2. 每层有多少个状态需要尝试
每一层新增的状态根据上一层来决定,如果上一层打印到了nums[st], 则这一层新增的状态是从 st + 1 到 nums.length - 1
划重点!
这个思路用到的是另外一种构建subset的方法:“每个size为k的subset都是由一个size为k-1的subset加上一个元素得到的”。
注意这里smallestCandidate这个变量的定义,它代表的是新添的元素最小的可能。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
backtrack(nums, 0, new ArrayList<>(), res);
return res;
}
private void backtrack(int[] nums, int smallestCandidate, List<Integer> path, List<List<Integer>> res){
res.add(new ArrayList<>(path));
for(int i = smallestCandidate; i < nums.length; i++){
path.add(nums[i]);
backtrack(nums, i + 1, path, res);
path.remove(path.size() - 1);
}
}
}