DFS

563.二叉树的深度
image.png

  1. class Solution {
  2. private int sum;
  3. public int findTilt(TreeNode root) {
  4. sum = 0;
  5. dfs(root);
  6. return sum;
  7. }
  8. private int dfs(TreeNode root){
  9. if (root == null) return 0;
  10. int ls = dfs(root.left);
  11. int rs = dfs(root.right);
  12. int ss = Math.abs(ls - rs);
  13. sum += ss;
  14. return ls + rs + root.val;
  15. }
  16. }

上面的代码是标准的DFS模板,对应数据结果是tree,如果是数组的话,left和right相当于数组的index。
对于递归代码,我们着重要考虑两点:

  1. 首先要定义好递归函数的定义
  2. 确定递归函数的退出条件,往往是答案找到或数据越界的情况

如上面该题中的dfs函数,其返回值定义为以root为根节点的整棵树的节点之和,因此我们自然而然就能得出该树的坡度=|dfs(left) - dfs(right)|,然后对每个节点的坡度进行累加即可得到结果
对于上题的退出条件很简单,即数据越界,树为空的情况。

回溯

90. 子集II
image.png

  1. class Solution {
  2. // 转换为相同元素选几次,如[1,1,1],如果选一个1,选第一个1和第三个1,结果是重复的
  3. // 所以转为选几个1,如1个1 -> 1 , 2个1-> 1,1 , 3个1 -> 1,1,1
  4. public List<List<Integer>> subsetsWithDup(int[] nums) {
  5. Arrays.sort(nums);
  6. List<List<Integer>> ans = new ArrayList<>();
  7. List<Integer> cur = new ArrayList<>();
  8. dfs(nums,0,ans,cur);
  9. return ans;
  10. }
  11. private void dfs(int[] nums , int index, List<List<Integer>> ans, List<Integer> cur){
  12. int n = nums.length;
  13. if (index == n){
  14. ans.add(new ArrayList<>(cur));
  15. return;
  16. }
  17. // 找相同元素范围,last是下一个不同元素位置
  18. int currentNum = nums[index];
  19. int last = index;
  20. while (last < n && nums[last] == currentNum){
  21. last++;
  22. }
  23. // 当前元素不选
  24. dfs(nums,last,ans,cur);
  25. // 当前元素选
  26. for (int i = index; i < last; i++) {
  27. cur.add(currentNum);
  28. // 注意dfs的位置是last,代表当前元素选了i次
  29. dfs(nums,last,ans,cur);
  30. }
  31. // 回溯当前元素选择,上面从index到last递增dfs了一遍,到这里肯定里面有last-index个当前元素,全部撤回
  32. for (int i = index; i < last; i++) {
  33. cur.remove(cur.size()-1);
  34. }
  35. }
  36. }

上面的代码是标准的回溯+DFS的模板代码。
一般对于回溯而言,每个DFS函数中都会有多个情况候选,因此需要对这些候选方案进行遍历,对每个子情况进行选择/不选择,注意遍历一个子情况就代表当前位置已经有了抉择,要进行递归下一轮DFS决定后面index的抉择,如果当前有选择子情况,递归回来后还要删除当前选择的子情况,继续对下个子情况进行相同方式的抉择。

一定要谨记每个DFS函数只对自己当前的index的情况进行遍历,后面递归的情况无需考虑,注意思维的抽象,选择之后进行回退删除。