如果有明显的递推痕迹,直接dp表顺序填写,考虑初始化的意义。如果没有规则需要探索,就考虑回溯,考虑合法的边界
Problem: LCR 079. 子集
思路
//站在 答案 的角度思考
//枚举第一个数 选谁。【选谁 也是对这个元素的 选或不选 操作 ---->回溯】
//枚举第二个数 选谁
//每个节点都是答案【由于子集的长度没有约束,每一个子集都可以是答案,每次递归都需要记录下答案】
//注意:【1,2】和 【2,1】是重复子集,
// 为了避免重复,下一个数应该大于当前选择的数
解题方法
// 递归入口和边界 [0~n)
// 当前操作?枚举 一个 下标 j>=i 的数字, 加入 pick
// 子问题? 从下标 >= i的数字中构造子集
// 下一个子问题? 从下标 >= j+1 的数字中构造子集
// dfs(i) ---> dfs(i+1)
// ---> dfs(i+2)
// ---> dfs(i..+k)
//. ---> dfs(n)
Code
class Solution {
int[] nums;
List<List<Integer>> res = new ArrayList<>();
List<Integer> pick = new ArrayList();
public List<List<Integer>> subsets(int[] nums) {
this.nums = nums;
int n = nums.length;
dfs(0);
return res;
}
public void dfs(int i){
//递归的每一个节点都是答案
res.add(new ArrayList<>(pick)); //copy固定答案
//不会走到这个判断,因为 下面的 for的右边界约束了
// if(i == nums.length){
// return;
// }
for(int j = i; j < nums.length ; j++){ //枚举选择的数字
pick.add(nums[j]);
dfs(j+1);
pick.remove(pick.size()-1); //恢复现场
}
}
}