day16 二叉树part3

二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)

而根节点的高度就是二叉树的最大深度,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度。
这一点其实是很多同学没有想清楚的,很多题解同样没有讲清楚。

遍历的顺序一定是左右中,中间是处理的过程(把孩子节点的深度返回给父节点)
day16 二叉树part3_第1张图片

104. 二叉树的最大深度

简单
给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数

难点:其实就是我们这棵二叉树的最大深度就是层数,这是层序遍历法的思想。但是递归要想到的话还是有点难度:

任何一个节点的高度,都是它左右子树最大高度加一,所以要知道根节点的高度,肯定要知道它子树的高度,要知道它子树的高度,肯定要知道它子树的子树的高度……因此,高度肯定是要从最下面往上面算出来的,可以通过递归,找到最深层的那个节点,然后一层一层地返回,直到抵达根节点,这就是要使用后序遍历的原因
单层递归的逻辑:先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。

class Solution {
    public int maxDepth(TreeNode root) {
        return getDepth(root);
    }

    public int getDepth(TreeNode node){
        if (node == null) {
            return 0;
        }
        int leftDepth = getDepth(node.left) ;
        int rightDepth = getDepth(node.right);

        return Math.max(leftDepth, rightDepth) + 1;
    }
}
// 层序遍历法
class Solution {
    public int maxDepth(TreeNode root) {
        int res = 0;
        if (root == null) {
            return res;
        }
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // while 循环控制从上向下一层层遍历
        while(!q.isEmpty()){
            int size = q.size();
            TreeNode curNode;
            res++;//该层深度自增

            // for 循环控制每一层从左向右遍历
            for (int i = 0; i < size; i++) {
                curNode = q.poll();   
                // 不断地把该层的不为空的孩子结点加入队列
                if(curNode.left != null) q.offer(curNode.left);
                if(curNode.right != null) q.offer(curNode.right);
            }
        }
        return res;
    }
}

111. 二叉树的最小深度

简单
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点

在处理节点的过程中,最大深度很容易理解,最小深度就不那么好理解,如图:
day16 二叉树part3_第2张图片
这就重新审题了,题目中说的是:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。,注意是叶子节点。

什么是叶子节点,左右孩子都为空的节点才是叶子节点!
day16 二叉树part3_第3张图片
如果这么求的话,没有左孩子的分支会算为最短深度。
所以,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。
反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。

class Solution {
    public int minDepth(TreeNode root) {
        int minDep = getMin(root);
        
        return minDep;
    }
    public int getMin(TreeNode node) {
        if (node == null) {
            return 0;
        }
        if (node.left == null && node.right == null) {
            return 1;
        }
        if (node.left == null && node.right != null) {
            return getMin(node.right) + 1;
        }
        if (node.left != null && node.right == null) {
            return getMin(node.left) + 1;
        }

        return Math.min(getMin(node.left), getMin(node.right)) + 1;

    }
}
// 层序遍历法
class Solution {
    public int minDepth(TreeNode root) {
        int minDep = 0;
        if (root == null) {
            return minDep;
        }
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // while 循环控制从上向下一层层遍历
        while(!q.isEmpty()){
            int size = q.size();
            TreeNode curNode;
            minDep++;//该层深度自增

            // for 循环控制每一层从左向右遍历
            for (int i = 0; i < size; i++) {
                curNode = q.poll();
                // 当发现一个叶子节点时就可以返回结果了
                if (curNode.left == null && curNode.right == null) return minDep;
                // 不断地把该层的不为空的孩子结点加入队列
                if(curNode.left != null) q.offer(curNode.left);
                if(curNode.right != null) q.offer(curNode.right);
            }
        }
        return minDep;
    }
}

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

简单
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
day16 二叉树part3_第4张图片
层序遍历法可以秒了。
递归的话,和求最小深度比较类似,可以如下:
day16 二叉树part3_第5张图片
利用完全二叉树的特性计算节点的方法(这个方法我没自己写,我觉得非常鸡肋,大概就是说,完全二叉树一定是由满二叉树组成的,满二叉树的节点数公式为:2^深度数 - 1,所以可以往下递归),写法如下:

class Solution {
    /**
     * 针对完全二叉树的解法
     *
     * 满二叉树的结点数为:2^depth - 1
     */
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        TreeNode left = root.left;
        TreeNode right = root.right;
        int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
        while (left != null) {  // 求左子树深度
            left = left.left;
            leftDepth++;
        }
        while (right != null) { // 求右子树深度
            right = right.right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}

递归通用写法:

 // 通用递归解法
class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftNum = countNodes(root.left);
        int rightNum = countNodes(root.right);

        return leftNum + rightNum + 1;  // 加一是加上本身节点,整体上是一个后序遍历
    }
}

你可能感兴趣的:(算法,数据结构)