Tree DFS

Tree DFS

Tree DFS

Tree上的DFS分为两种(Divide Conquer + Traversal和纯Divide Conquer)

  • 建立当前/用全局变量(根据不同的方式)
  • root返回什么/更新指针)
  • 节点和节点,用root构建当前解(返回什么/更新指针)
  • 节点和节点,用左右构建当前
  • 返回当前/选择

Divide Conquer + Traversal

  1. 不同

    • 一般没有全局变量,创建当前变量作为当前最终解
    • 通过节点的最终解和节点的最终解,计算并更新当前变量
    • 判断节点的最终解,节点的最终解,当前变量,在三个解中选择一个
    • 作为当前层的最终解
      • 返回
      • 更新传入的参数指针
    • 有时会单独建立class Result
  2. 流程

    • 建立当前变量(不一定第一步)
    • root返回什么)
    • left节点和right节点,用root构建当前解(返回什么/更新指针)
    • left节点和right节点,用左右leftResult, rightResult计算当前
    • 选择符合的解
      • 比较leftResultrightResultresult+ 选出合适的解
      • 直接使用:当前解
    • 使用选中的解
      • 返回
      • 更新传入的指针
  3. 例题(Minimum Subtree)

    public class Solution {
    class Result {
    TreeNode minSubtree;
    int minSum;
    int sum;
    Result(TreeNode minSubtree, int minSum, int sum) {
    this.minSubtree = minSubtree;
    this.minSum = minSum;
    this.sum = sum;
    }
    }
    public TreeNode findSubtree(TreeNode root) {
    return dfs(root).minSubtree;
    }
    private Result dfs(TreeNode root) {
    if (root == null) {
    return new Result(root, Integer.MAX_VALUE, 0);
    }
    Result left = dfs(root.left);
    Result right = dfs(root.right);
    if (left.minSubtree == null && right.minSubtree == null) {
    return new Result(root, Integer.MAX_VALUE, root.val);
    }
    int currSum = left.sum + right.sum + root.val;
    Result curr = new Result(root, currSum, currSum);
    if (left.minSubtree != null) {
    if (left.minSum <= curr.minSum) {
    curr.minSubtree = left.minSubtree;
    curr.minSum = left.minSum;
    }
    }
    if (right.minSubtree != null) {
    if (right.minSum <= curr.minSum) {
    curr.minSubtree = right.minSubtree;
    curr.minSum = right.minSum;
    }
    }
    return curr;
    }
    }
  4. 例题(Binary Tree Paths)

    • 直接返回最终解

      public class Solution {
      public List<String> binaryTreePaths(TreeNode root) {
      return dfs(root, new StringBuilder());
      }
      private List<String> dfs(TreeNode root, StringBuilder sb) {
      List<String> result = new ArrayList<>();
      if (root == null) {
      return result;
      }
      if ((root.left == null) && (root.right == null)) {
      sb.append(String.valueOf(root.val));
      result.add(sb.toString());
      return result;
      }
      int index = sb.length();
      if (root.left != null) {
      sb.append(root.val + "->");
      List<String> leftResult = dfs(root.left, sb);
      sb.delete(index, sb.length());
      for (String item: leftResult) {
      result.add(item);
      }
      }
      if (root.right != null) {
      sb.append(root.val + "->");
      List<String> rightResult = dfs(root.right, sb);
      sb.delete(index, sb.length());
      for (String item: rightResult) {
      result.add(item);
      }
      }
      return result;
      }
      }
    • 更新全局变量

      public class Solution {
      public List<String> binaryTreePaths(TreeNode root) {
      List<String> result = new ArrayList<>();
      dfs(root, new StringBuilder(), result);
      return result;
      }
      private void dfs(TreeNode root, StringBuilder sb, List<String> result) {
      if (root == null) {
      return;
      }
      if (root != null && root.left == null && root.right == null) {
      sb.append(String.valueOf(root.val));
      result.add(sb.toString());
      return;
      }
      int index = sb.length();
      if (root.left != null) {
      sb.append(root.val + "->");
      dfs(root.left, sb, result);
      sb.delete(index, sb.length());
      }
      if (root.right != null) {
      sb.append(root.val + "->");
      dfs(root.right, sb, result);
      sb.delete(index, sb.length());
      }
      }
      }

Divide Conquer

  1. 不同

    • 一般全局变量,直接返回/打擂台
    • 最终解作为最终返回值
    • 通过节点的最终解和节点的最终解,更新当前最终解
    • 当前最终解作为全局最终解直接返回
  2. 流程

    • root返回什么)
    • 节点和节点,用root构建当前解(返回什么)
    • 节点和节点,用左右构建当前
    • 使用当前最终解返回
  3. 例题(Minimum Subtree)

    public class Solution {
    private TreeNode minSubtree;
    private int minSum;
    public TreeNode findSubtree(TreeNode root) {
    // 这里minSum不能设为root.val
    // 如果最初是root是最小子树,应该设置成root.val + leftSum + rightSum
    // 但是此时我们不知道leftSum和rightSum,所以就默认leftSum和rightSum是Integer.MAX_VALUE
    // 加在一起为了不溢出,就直接设置成Integer.MAX_VALUE
    this.minSum = Integer.MAX_VALUE;
    this.minSubtree = root;
    dfs(root);
    return this.minSubtree;
    }
    private int dfs(TreeNode root) {
    if (root == null) {
    return 0;
    }
    int leftSum = dfs(root.left);
    int rightSum = dfs(root.right);
    if (leftSum == 0 && rightSum == 0) {
    if (root.val <= minSum) {
    minSubtree = root;
    minSum = root.val;
    }
    return root.val;
    }
    int sum = leftSum + rightSum + root.val;
    if (sum <= minSum) {
    minSubtree = root;
    minSum = sum;
    }
    return sum;
    }
    }
  4. 例题(Binary Tree Paths)

    • 左右结果构建当前解,直接返回当前解给上一层
      public class Solution {
      public List<String> binaryTreePaths(TreeNode root) {
      List<String> result = new ArrayList<>();
      if (root == null) {
      return result;
      }
      List<String> leftList = binaryTreePaths(root.left);
      List<String> rightList = binaryTreePaths(root.right);
      if ((leftList == null || leftList.size() == 0) && (rightList == null || rightList.size() == 0)) {
      result.add(String.valueOf(root.val));
      return result;
      }
      if (leftList != null && leftList.size() > 0) {
      for (String item: leftList) {
      result.add(root.val + "->" + item);
      }
      }
      if (rightList != null && rightList.size() > 0) {
      for (String item: rightList) {
      result.add(root.val + "->" + item);
      }
      }
      return result;
      }
      }

Comments

Popular posts from this blog

Union Find 模板

Tree的经典题