随想录训练营14/60 | LC 104.二叉树的最大深度;LC 559.n叉树的最大深度;LC 111.二叉树的最小深度;LC 222.完全二叉树的节点个数

文章介绍了如何计算二叉树和n叉树的最大深度,包括层次遍历和递归深度优先遍历的方法。通过前序、后序遍历的思路,阐述了不同遍历方式在计算深度中的应用,并提供了相关代码示例。同时提到了二叉树最小深度的计算以及完全二叉树节点个数的判断。
摘要由CSDN通过智能技术生成

LC 104.二叉树的最大深度

题目链接 LC 104.二叉树的最大深度
思路首先要理解深度和高度的区别,然后理解二叉树的高度和深度以及节点的高度和深度。
二叉树的深度为从根节点往下走到叶子节点的路径长度,最大深度就是到最远叶子节点的长度。
节点的深度为从根节点到指定节点(节点不一定为叶子节点)的路径长度。
二叉树的高度从根节点向下遍历到叶子节点的长度,树的最大高度和最大深度是相同的
节点的高度为从指定接待你向下遍历到叶子节点的长度。
本题为计算二叉树的最大深度,在第13天训练营中,使用层次遍历(迭代法)来计算最大深度。还可以用深度遍历(递归法)来计算最大深度。
递归深度遍历,可使用前序遍历或者后序遍历来计算最大深度。前序遍历计算的是根节点到指定节点的深度,后序遍历计算的是从叶子节点到指定节点的高度。而当计算树的最大深度时,前序遍历的指定节点为叶子节点,后序遍历的指定节点为根节点,结果相同。
前序遍历的思路为:每次先处理中间节点,若中间节点的深度比全局深度大,则更新全局深度;然后判断中间节点的左右子树是否为空,若都为空,则返回(返回条件);若(左或者右)不为空,(左或者右)深度加一,让节点先进入递归,出来后,深度减一(入栈深度加一,出栈深度减一)(为什么要出栈深度减一,因为后面的节点深度要通过正确的深度来进行更新,所以每个递归的输入就是每个节点的地址和节点的深度,所以深度要随时更新,这也体现了一部分回溯的思路)。
后序遍历的思路为:递归的输入为节点地址,输出为节点的高度(因为当我们输入一个空节点时返回的是0);分析返回条件,当遍历到空节点是就返回。若不是空节点,就先递归左子树,并且保存左子树的高度,再递归右子树保存右子树的高度,该节点的高度就是左右子树取最大然后加一。
为什么先序遍历递归需要输入节点的深度,而后序遍历递归不用输入节点的高度,因为节点的深度是从上至下,也就是节点进入栈的顺序,所以要输入节点的深度,不然不知道节点的深度;后序遍历虽然也是从上至下让节点入栈,但是在出栈的时候来统计节点的高度,若为叶子节点则为0,并且会返回每个节点的最大高度,所以不用在递归的时候传入高度值。
代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //迭代层次遍历
    int maxDepth(TreeNode* root) {
        int result = 0;
        queue<TreeNode*> que;
        if(root)que.push(root);
        while(!que.empty()){
            int size = que.size();
            while(size--){
                TreeNode* cur = que.front();
                que.pop();
                if(cur->left)que.push(cur->left);
                if(cur->right)que.push(cur->right);
            }
            result++;
        }
        return result;
    }
    //递归深度优先遍历(后序遍历)
    int getHeight(TreeNode* cur){//输入是节点地址,输出是该节点的高度,当节点为空节点时,高度为0;当节点为叶子节点时,高度为1
        //返回条件
        if(cur==nullptr)return 0;//要包括输入为空节点的情况
        //不然先遍历左子树,再遍历右子树,最后处理中间节点
        int leftHeight = getHeight(cur->left);
        int rightHeight = getHeight(cur->right);
        int result = max(leftHeight, rightHeight) + 1;
        return result;

    }
    int maxDepth(TreeNode* root) {
        int result = getHeight(root);
        return result;
    }
    //递归深度遍历(先序遍历)有点困难,但是仍然需要掌握
    int resultD;//需要一个全局变量保存结果
    void getDeep(TreeNode* cur, int depth){//输入是节点地址和节点的深度,根节点不为空则深度为1,为空则深度为0
        //先处理中间节点
        //若根节点深度小于节点深度,就更新根节点深度
        resultD = depth > resultD ? depth : resultD;
        //返回条件
        if(cur->left==nullptr && cur->right==nullptr)return;//若为叶子节点返回
        //不然先遍历左子树,再遍历右子树
        if(cur->left){depth++;getDeep(cur->left, depth);depth--;}
        if(cur->right){depth++;getDeep(cur->right, depth);depth--;}
    }
    int maxDepth(TreeNode* root) {
        resultD = 0;
        if(root==nullptr)return resultD;
        getDeep(root, 1);
        return resultD;
    }
};

LC 559.n叉树的最大深度

题目链接LC 559.n叉树的最大深度
思路:和求二叉树深度相同
代码

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    //迭代法,层次遍历
    int maxDepth(Node* root) {
        int result = 0;
        queue<Node*> que;
        if(root)que.push(root);
        while(!que.empty()){
            int size = que.size();
            while(size--){
                Node* cur = que.front();
                que.pop();
                int c = cur->children.size();
                for(int i=0; i<c; i++){
                    que.push(cur->children[i]);
                }
            }
            ++result;
        }
        return result;
    }
    //递归,深度遍历(后序)
    int getDepth(Node* cur){
        int result=0;
        if(cur==nullptr)return result;
        int size = cur->children.size();
        for(int i=0; i<size; i++){
            result = max(result, getDepth(cur->children[i]));
        }
        result = result+1;
        return result;
    }
    int maxDepth(Node* root) {
        int result = getDepth(root);
        return result;
    }
};

LC 111.二叉树的最小深度

题目链接LC 111.二叉树的最小深度
思路:层次遍历,当遇到叶子节点就break,返回深度。
递归后序遍历,当遇到左右子树其中一个子树为空时,要注意,不能用最小子树高度加一得到节点最小高度。当遇到左右子树都为空或者都不为空时,可以通过取左右子树最小高度加一来得到节点的最小高度。
代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //迭代法,层次遍历
    int minDepth(TreeNode* root) {
        int result;
        queue<TreeNode*> que;
        if(root){que.push(root);result = 1;}
        else{result = 0;}
        while(!que.empty()){
            int size = que.size();
            while(size--){
                TreeNode* cur = que.front();
                que.pop();
                if(cur->left==nullptr && cur->right==nullptr)return result;
                if(cur->left)que.push(cur->left);
                if(cur->right)que.push(cur->right);
            }
            result++;
        }
        return result;
    }
    //递归法,深度优先遍历(后序遍历)
    int getMinDe(TreeNode* cur){//当遇到叶子节点时
        if(cur==nullptr)return 0;
        int left = getMinDe(cur->left);//前面不用判断,因为若为空也无妨,若判断了,则不会定义int,会报错
        int right = getMinDe(cur->right);
        //cur的左右子树可能为空,但是若只有一边为空,该节点仍不是叶子节点,所以不能用left和right的最小值来得到最小深度
        //当两边都为空或两边都不为空时,可以通过两个子树高度的最小值加一得到节点的高度
        if(cur->left!=nullptr && cur->right==nullptr){return left+1;}
        if(cur->right!=nullptr && cur->left==nullptr)return right+1;
        //当两个都不为空,或者两个都为空时
        int result = min(left, right) + 1;
        return result;
    }
    int minDepth(TreeNode* root) {
        int result = getMinDe(root);
        return result;
    }
};

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

题目链接LC 222.完全二叉树的节点个数
思路:首先可以将其看成普通二叉树来求解,有两种方案,第一递归法,用后序遍历进行递归,每次加上左右子树节点和自身节点作为总节点数;第二迭代法,用层次遍历,来获取节点的数目。
然而这道题给了完全二叉树的约束,那么可以用以下思路:
首先判断节点是否为空,若为空则返回0;
然后计算节点的左右子树深度,若左右子树深度(最左边和最右边的深度)相同,那么说明该树(子树)为满二叉树,就用公式直接计算节点总节点个数,否则就进行递归,分别得到左右两个子树的节点个数,然后加一,得到总的节点个数。
代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //层次遍历,迭代法
    int countNodes(TreeNode* root) {
        int result = 0;
        queue<TreeNode*> que;
        if(root!=nullptr)que.push(root);
        while(!que.empty()){
            int size = que.size();
            result += size;
            while(size--){
                TreeNode* cur = que.front();
                que.pop();
                if(cur->left)que.push(cur->left);
                if(cur->right)que.push(cur->right);
            }
        }
        return result;
    }

    //当作普通二叉树进行后序遍历
    int countNodes(TreeNode* root) {
        if(root==nullptr)return 0;
        int left = countNodes(root->left);
        int right = countNodes(root->right);

        int result = left + right + 1;
        return result;
    }

    //作为完全二叉树来 处理,通过判断树(或者子树)是否为满二叉树来进行剪枝处理
    int countNodes(TreeNode* root) {
        if(root==nullptr)return 0;

        //剪枝处理,判断节点下是否时满二叉树
        TreeNode* leftNode = root->left;
        TreeNode* rightNode = root->right;
        int leftLength = 0;
        int rightLength = 0;
        //左边的深度
        while(leftNode){
            leftNode = leftNode->left;
            leftLength++;
        }
        //右边的深度
        while(rightNode){
            rightNode = rightNode->right;
            rightLength++;
        }
        //当两点深度相同时就是满二叉树,就可以用公式计算总节点个数
        if(rightLength==leftLength)return (2<<leftLength)-1;//leftLength为左边的深度,总深度为leftLength+1,总节点数为2^{0}+...+2^{leftLength}=2^{leftLength+1}-1
        //若不是满二叉树就进行以下操作
        int left = countNodes(root->left);
        int right = countNodes(root->right);
        int result = left + right + 1;
        return result;
    }
};

总结

在递归法中,前序遍历一般适用于翻转二叉树(也可用后序,但中序需要注意)
后序遍历一般适用于对称二叉树(不是完全的后序,而是说从叶子节点开始判断是否是对称的),二叉树的最大深度、二叉树的最小深度,完全二叉树的节点个数
层次遍历一般适用于二叉树的最大深度、二叉树的最小深度,完全二叉树的节点个数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值