Binary Tree Upside Down

  • Medium
  • keyword: map
  • 类似: 2 sum closest

题目意思: Given a binary tree where all the right nodes are either [leaf nodes with a sibling (a left node that shares the same parent node)] OROROROR [empty], flip it upside down and turn it into a tree where the original right nodes turned into left leaf nodes. Return the new root.

  • 没看懂这个OROROROR是的断句是断在哪里. 看来是英文没学好: 这个or显然是: either A or B. 见我在原题目所加的中括号. 所以题目意思就是: 所有右儿子要么是空, 要么就是叶子节点而且有左兄弟.
  • 也可以说: 所有右儿子都没有子树!
  • 大致思路: 图解: http://www.1point3acres.com/bbs/forum.php?mod=redirect&goto=findpost&ptid=130961&pid=1857539&fromuid=196530

idea1.1: recursion bottom-up

  • 很直白的解法: 其实就是discuss: explain: Binary tree representation of N-ery trees
  • 翻译过来就是:

    • 递归向下的直到left-most leaf, 这个是反转后的newRoot. 然后walk-up tree, 将root.left指向root.sibling, 将root.right指向root.parent.
    • 由于root.sibling/parent只有walk-up tree的时候才能处理, 所以放在recursion call之后处理.
  • 由于要在walk up的时候指向parent/sibling. 所以我在recur.param里面使用stack保存向下走的时候的right kid. 同时由于最终返回的newRoot其实是确定的, 就是left-most leaf, 所以用一个array保存它.

  • 在walk up的时候, 将newRoot.left指向stack.pop, 将newRoot.right指向root. 并且返回的是newRoot的更新后的右儿子.

  • 代码如下

public TreeNode upsideDownBinaryTreeSLOW(TreeNode root) {
    TreeNode[] ans = new TreeNode[1];
    TreeNode res = helper(root, new Stack<TreeNode>(), ans) ;
    return ans[0];
  }

private TreeNode helper(TreeNode root, Stack<TreeNode> stk, TreeNode[] ans) {
    if (root.left == null && root.right == null) {
        ans[0] = root;
        return root;
    }
    TreeNode upRoot = helper(root.left, stk, ans);
    upRoot.left = stk.pop();
    upRoot.right = root;
    return upRoot.right; // 注意返回值不是upRoot! 而是upRoot.right, 从而向上走并且update其指针.
}
  • 结果排名垫底.

idea1.2: 还是recursion bottom-up

  • 这里参考的是Leetcode discuss
  • 思路类似, 但是注意到, recursion call的返回值始终指向最终newRoot. 所以方法和recursion解决LinkedList reverse一样, 参考yuanbin的gitbook.
  • 代码如下
public TreeNode upsideDownBinaryTreeSLOW(TreeNode root) {
    TreeNode res = helper(root) ;
    return res;
  }

private TreeNode helper(TreeNode root) {
    if (root == null || root.left == null && root.right == null) {  // 第一个判断条件很好的解决了corner case
        return root;
    }
    TreeNode newRoot = helper(root.left);
    root.left.left = root.right;  // 处理root.left
    root.left.right = root;
    root.left = null;  // 处理root. 注意不要cyclic了
    root.right = null;
    return newRoot;  // 始终指向left-most leaf
}
  • 思路和idea2类似, 但是多一个param保存parent, 这样walk-up的时候可以一直走到老root.
  • 代码如下
public TreeNode upsideDownBinaryTreeSLOW(TreeNode root) {
    TreeNode res = helper(root, null) ;
    return res;
  }

private TreeNode helper(TreeNode root, TreeNode parent) {
    if (root == null) {
        return parent;
    }
    TreeNode newRoot = helper(root.left, root);
    root.left = parent == null ? parent : parent.right;  // 合并了root, root.left的update到一起.
    root.right = parent;
    return newRoot;  // 始终指向left-most leaf
}

小结

  • recursion的方法很好的解决了overwrite的问题, 因为walk-down到bottom的时候才向上overwrite.
  • 看看1.2和1.3方法的代码的区别, cpcs和discuss的方法类似, 但是cpcs将root和root.left的update放在了一起. 很妙.
  • 其实这个题目在理解了题意之后就知道, 其实和reverse LinkedList一样, 只不过从1个pointer变成2个pointer.

idea2: iteration解决问题

  • 代码如下, Leetcode discuss讲得好:

    Just think about how you can save the tree information you need before changing the tree structure.

private TreeNode iteration(TreeNode root) {
    TreeNode curr = root;
    TreeNode prev = null;
    TreeNode temp = null;
    TreeNode next = null;

    while (curr != null) {
      next = curr.left;
      curr.left = temp;
      temp = curr.right;
      curr.right = prev;

      prev = curr;
      curr = next;
    }
    return prev;
  }