【代码训练营】day16 | 104.二叉树的最大深度 & 559.n叉树的最大深度 & 111.二叉树的最小深度 & 222.完全二叉树的节点个数

106 阅读3分钟

所用代码 java

二叉树的最大深度 LeetCode104

题目链接: 二叉树的最大深度 LeetCode104 - 简答

思路

深度指的是从上往下数,一层深度就是1,总共二叉树有几层,深度就是几。深度一般是前序遍历,而求高度一般是后续遍历。

递归法 DFS

class Solution {
    public int maxDepth(TreeNode root) {
        return traversal(root,0);
    }
​
    // 前序遍历
    public int traversal(TreeNode node, int deep){
        if (node == null) return deep;
        // 每次进来就深度就 + 1
        deep++;
        int left = traversal(node.left, deep);
        int right = traversal(node.right, deep);
        return left > right ? left : right;
    }
    
    // 后续遍历 深度=高度
    public int traversal1(TreeNode node){
        if (node == null) return 0;
        int left = traversal(node.left);
        int right = traversal(node.right);
        // 高度每次往上递增
        int maxHeight = 1 + Math.max(left, right);
        return maxHeight;
        // return 1 + Math.max(traversal(node.left), traversal(node.right));
    }
}

层序遍历 BFS

public int maxDepth(TreeNode root) {
    int deep = 0;
    Deque<TreeNode> deque = new ArrayDeque<>();
    if (root != null) deque.offer(root);
    while (!deque.isEmpty()){
        // 每进入一层,深度加一
        deep++;
        int size = deque.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = deque.poll();
            if (node.left != null) deque.offer(node.left);
            if (node.right != null) deque.offer(node.right);
        }
    }
    return deep;
}

总结

一般来说求深度就可以看成求高度,然后就可以用后序遍历的方式进行递归,而且可以把代码写的很极简,一行就可以搞定,但是不建议这样写,因为只有写清楚过程我们才能知道遍历的顺序。另外本题层序遍历也是非常的清晰,但是会消耗更多的空间。

n叉树的最大深度 LeetCode559

题目链接:n叉树的最大深度 LeetCode559 - 简单

思路

同二叉树的一样

递归 BFS

class Solution {
    public int maxDepth(Node root) {
        return traversal(root);
    }
​
    public int traversal(Node node){
        if (node == null) return 0;
        // 这个必须令deep=0,以便孩子结点在往下搜索时deep一直增长
        int deep = 0;
        List<Node> children = node.children;
        for (Node child : children){
            int height = traversal(child);
            deep = Math.max(deep, height);
        }
        return deep + 1;
    }
}

层序遍历 DFS

class Solution {
    public int maxDepth(Node root) {
        int deep = 0;
        Deque<Node> deque = new ArrayDeque<>();
        if (root != null) deque.offer(root);
        while (!deque.isEmpty()){
            // 每遍历一层深度便加一
            deep++;
            int size = deque.size();
            for (int i = 0; i < size; i++) {
                Node node = deque.poll();
                List<Node> children = node.children;
                for (Node child : children){
                    deque.offer(child);
                }
            }
        }
        return deep;
    }
}

总结

总感觉使用层序要简单一点,更符合人类的思考方式。

二叉树的最小深度 LeetCode111

题目链接:二叉树的最小深度 LeetCode111 - 简单

思路

和最大深度做法一样

递归法 DFS

class Solution {
    public int minDepth(TreeNode root) {
        return traversal(root);
    }
​
    public int traversal(TreeNode node){
        if (node == null) return 0;
        int left = traversal(node.left);
        int right = traversal(node.right);
​
        // 中  需要考虑往一边走的情况,也就是只有一个子树
        if (node.left == null && node.right != null){
            return right + 1;
        }
        if (node.left != null && node.right == null){
            return left + 1;
        }
        int minDepth = Math.min(left, right) + 1;
        return minDepth;
    }
​
}

层序遍历BFS

class Solution {
    public int minDepth(TreeNode root) {
        int deep = 0;
        Deque<TreeNode> deque = new ArrayDeque<>();
        if (root != null) deque.offer(root);
        while (!deque.isEmpty()){
            int size = deque.size();
            // 每进入一层,深度就+1
            deep++;
            for (int i = 0; i < size; i++) {
                TreeNode node = deque.poll();
                // 该结点为叶子结点就返回
                // 因为我们是从上往下,从左往右遍历,出现叶子结点一定是最小的深度
                if (node.left == null && node.right == null){
                    return deep;
                }
                if (node.left != null) deque.offer(node.left);
                if (node.right != null) deque.offer(node.right);
            }
        }
        return deep;
    }
}

总结

求二叉树的最小深度和最大深度是差不多的,主要区别就是中结点的处理上,要注意什么是最小的深度,必须有子结点的才算,所以求最小深度有一个判断的过程。

完全二叉树的节点个数 LeetCode 222

题目链接:完全二叉树的节点个数 LeetCode 222 - 中等

思路

1、普遍二叉树的方法

class Solution {
    int num = 0;
    public int countNodes(TreeNode root) {
        traversal(root);
        return num;
    }
​
    public void traversal(TreeNode root){
        if (root == null) return;
        num++;
        traversal(root.left);
        traversal(root.right);
    }
}
​
// 后序的写法,不用再定义一个num进行遍历
    public int postTraversal(TreeNode root){
        if (root == null) return 0;
        int left = postTraversal(root.left);
        int right = postTraversal(root.right);
        // 结点数量 = 左孩子的结点数量 + 右孩子的结点数量 + 自己(1)
        int num = left + right + 1;
        return num;
}

2、利用完全二叉树的性质,除了最下边一层,上边是满二叉树满二叉树的结点个数为2^k - 1,k为深度,就不用把每一个结点都遍历完。

class Solution {
    public int countNodes(TreeNode root) {
        return CompleteTree(root);
    }
​
    public int CompleteTree(TreeNode node){
        // 返回情况1:遇到空结点
        if (node == null) return 0;
        // 返回情况2:是完全二叉树的情况
        TreeNode leftNode = node.left;
        TreeNode rightNode = node.right;
        int leftDepth = 0;
        int rightDepth = 0;
        // 计算左侧深度
        while (leftNode != null){
            leftNode = leftNode.left;
            leftDepth++;
        }
        // 计算右侧深度
        while (rightNode != null){
            rightNode = rightNode.right;
            rightDepth++;
        }
        // 判断两侧深度是否相等,相等则为满二叉树
        if (leftDepth == rightDepth){
            // 2<<1 2左移一位相等于2的2次方
            // 根据下边,右边为2^0 左移增加位数
            // 256 128 64 32 16 8 4 2 1
            return (2 << leftDepth) - 1;
        }
​
        // 开始进行递归 - 后序
        int leftNum =  CompleteTree(node.left);
        int rightNum = CompleteTree(node.right);
        // 自己结点的数量 = 左子树数量 + 右子树数量 + 自己(1)
        int num = leftNum + rightNum + 1;
        return num;
    }
}

总结

这个题考的是我们能否利用完全二叉树的性质来完成,完全二叉树只有底层不是满的,上层是满二叉树,而满二叉树可以快速的计算出结点的个数,就不用把所有的结点都遍历一遍。