代码随想录算法训练营第16天|104. 二叉树的最大深度、111. 二叉树的最小深度、222. 完全二叉树的节点个数

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

题目链接

视频链接

思路:

从底部开始,逐个加1后返回上层

看完代码随想录之后的思路:

因为是算最大深度,所以可以等同于算根部的高度,用后序遍历,逐个加一后返回上层

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root==NULL)return 0;
        
        int left=maxDepth(root->left);
        int right=maxDepth(root->right);
        int depth=max(left,right)+1;
        
        return depth;
    }
};

收获:

算高度:一般采用后续遍历,因为越靠近根部,高度越高

算深度:一般采用前序遍历,因为越靠近根部,深度越浅

正常的前序算深度,需要用到回溯,后面再补

111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

题目链接

视频链接

思路:

类似最大的深度,在左右算完之后,在中间取最小。(但是会出现空节点算最小的情况)

看完代码随想录之后的思路:

在最后中节点计算时,需要首先排除空节点的情况。

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root==NULL)return 0;
        
        int left_depth=minDepth(root->left);
        int right_depth=minDepth(root->right);
       
        int depth=0;
        if(root->left==NULL&&root->right!=NULL)depth=1+right_depth;
        else if(root->left!=NULL&&root->right==NULL)depth=1+left_depth;
        else depth=1+min(left_depth,right_depth);

        return depth;
    }
};

遇到的困难:

二叉树递归就是要向左向右遍历,不存在向左向右递归会漏的情况,所以不用纠结。

判断空节点不是只有根节点才会有这个情况,是所有节点都会存在这个情况,所以可以写在递归的函数中,整体作为中节点的代码。

判断空节点后,不只是选择不空的子树,还需要在子树节点的基础上加1返回

//补充一段官方的代码,重点看看判断空节点后的操作
class Solution {
public:
    int getDepth(TreeNode* node) {
        if (node == NULL) return 0;
        int leftDepth = getDepth(node->left);           // 左
        int rightDepth = getDepth(node->right);         // 右
                                                        // 中
        // 当一个左子树为空,右不为空,这时并不是最低点
        if (node->left == NULL && node->right != NULL) { 
            return 1 + rightDepth;
        }   
        // 当一个右子树为空,左不为空,这时并不是最低点
        if (node->left != NULL && node->right == NULL) { 
            return 1 + leftDepth;
        }
        int result = 1 + min(leftDepth, rightDepth);
        return result;
    }

    int minDepth(TreeNode* root) {
        return getDepth(root);
    }
};

收获:

在前面return执行的话,就不会执行下面的代码了,相当于一个else if

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

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

题目链接

视频链接

思路:

后续遍历逐个加一

看完代码随想录之后的思路:

因为是完全二叉树,所以可以利用从左到右不断的特性,来判断是否为满二叉树,如果是满二叉树,使用2^n-1的方法会极大地减少运算时间

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root==NULL)return 0;
        TreeNode* left=root->left;
        TreeNode* right=root->right;
        int left_num=0;
        int right_num=0;

        while(left){
            left=left->left;
            left_num++;
        }
        while(right){
            right=right->right;
            right_num++;
        }

        if(left_num==right_num)return (2<<left_num)-1;
        else{
            left_num=countNodes(root->left);
            right_num=countNodes(root->right);
            return left_num+right_num+1;
        } 
    }
};

收获:

位移操作的优先级小于加减,所以位运算要加括号

重点:

先算左节点和右节点的数量是否相等,不相等之后要用递归。前面判断的操作相当于剪枝,递归的核心部分在最后的else中(因为前面用了return,所以这里可以不用else,直接接在下面写就可以)