Recursive Thinking in Binary Tree

在用递归实现Binary Tree的时候总结下来需要具备宏观思维和微观思维

什么是宏观思维呢?宏观思维就是递归三要素,也就是递归函数的定义(输入是什么,输出是什么,返回值类型是什么,以及最重要的这个函数在做一件什么事情),函数拆解(当前节点的结果是如何通过它的左子树和右子树得来的),以及退出条件(什么情况下可以直接得到结果,或者什么情况下退出递归函数)

什么是微观思维呢?微观思维就是递归过程中如何进栈,如何出栈,是自顶向下还是自下而上,当前节点的函数值如何得到。比如tree的三种traverse,在traverse的过程中,每一个节点是什么时候进栈,然后什么时候再出栈。

下面是的几个关于Binary Tree Depth例子可以很好的了解宏观思维以及微观思维

题目1: Maximum Depth of Binary Tree

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

思路分析:这道题通过宏观思维的方式来考虑:

递归函数定义:递归函数要做的事情是找到当前节点的maxDepth,输入是当前节点,输出(返回值)是这个节点的maxDepth

递归函数拆解:当前节点的maxDepth是如何通过它的左子树的maxDepth和右子树的maxDepth得到的?如果已经知道了当前节点的左,右子树的maxDepth,那么从这两个中选出那个最大的然后加上1就得到了当前节点的maxDepth

递归函数退出条件:什么时候可以不用递归而直接得到结果呢?那就是当root为null的时候可以直接得到它的maxDepth为0

那么知道了上面的宏观思维,就可以很容易用code进行实现了:

class Solution {
    public int maxDepth(TreeNode root) {    <<<<递归函数的定义
        if (root == null) return 0;   <<<<递归函数退出条件
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;    <<<<递归函数的拆解
    }
}

题目2: Balanced Binary Tree

Given a binary tree, determine if it is height-balanced.

For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees ofeverynode never differ by more than 1.

思路分析:这道题通过宏观思维的方式来考虑:

递归函数定义:递归函数要做的事情是判断以当前节点为根节点的tree是不是height-balanced binary tree,输入是当前节点,输出(返回值)是以此节点为根节点的tree是不是height-balanced binary tree

递归函数拆解:当前节点为根节点的tree是不是height-balance tree是如何通过它的左右子树是不是height-balanced tree来得到的呢?是由三种情况的组合得到的,左子树是不是height-balanced tree,右子树是不是height-balanced tree,以及左右子树的高度差是不是小于等于1。第三种情况可以通过辅助函数treeHeight来得到。

递归函数退出:什么时候可以不用递归而直接得到结果呢?当root为null的时候可以直接得到函数值true。

知道了上面的宏观思维,就可以很容易用code进行实现了:

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return Math.abs(treeHeight(root.left) - treeHeight(root.right)) <=1 && isBalanced(root.left) && isBalanced(root.right);
    }
    public int treeHeight(TreeNode root){
        if (root == null) return 0;
        return Math.max(treeHeight(root.left), treeHeight(root.right)) + 1;
    }
}

题目3: Find Leaves of Binary Tree

Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.

Example:
Given binary tree

          1
         / \
        2   3
       / \     
      4   5

Returns[4, 5, 3], [2], [1].

Explanation:

  • Removing the leaves[4, 5, 3]would result in this tree:
          1
         / 
        2
  • Now removing the leaf[2]would result in this tree:
          1
  • Now removing the leaf[1]would result in the empty tree:
          []

Returns[4, 5, 3], [2], [1].

思路分析:这道题乍一看应该是用DFS来做,但是具体该怎么实现却不是很清晰。这道题的核心是要找到每个节点的高度,相同高度的节点放在同一个list里面,比如节点4,5,3的高度都是0,节点2的高度是1, 节点1的高度是2。

所以这道题在宏观上比较难把握,只是知道需要找到每一个节点的高度。所以这道题要理解从微观上每一个节点要如何出栈,如何入栈。首先节点要通过post order的方式进行遍历,以这道题的树为例,首先节点1入栈,然后节点2入栈,然后节点4入栈,节点4是叶子节点,其高度为1,放进高度为1的list中,然后节点4出栈,遍历到了节点2的右子树,也就是节点5,节点5也是叶子节点,高度为1,也将其放进高度为1的list中。然后节点5出栈,这个时候栈底是节点2,节点2的高度为2,将节点2放进高度为2的list中,然后节点2出栈,到达节点1的右子树,也就是节点3,节点3的高度为1,将其放到高度为1的list中,然后出栈。最后到达节点1,节点1的高度为3,故将其放到高度为3的list中。

根据上面的微观分析,可以看出一边通过post order遍历所有节点的方式找到每一个节点的高度,一边把相同高度的节点放到相应的list中。

class Solution {
    public List<List<Integer>> findLeaves(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        treeHeight(root, result);
        return result;
    }
    public int treeHeight(TreeNode root, List<List<Integer>> result){
        if (root == null) return -1;
        int height = Math.max(treeHeight(root.left, result), treeHeight(root.right, result)) + 1;
        if (result.size() == height){
            result.add(new ArrayList<Integer>());
        }
        result.get(height).add(root.val);
        root.left = null;
        root.right = null;
        return height;
    } 
}

results matching ""

    No results matching ""