代码随想录算法训练营第16天

二叉树part03

104.二叉树的最大深度

题目

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

思路

这道题有两种解法,先说递归解法。
递归有两种思路,一种是求树的深度(前序遍历),一种是求树的高度(后序遍历)。

递归解法1(求深度)

先说求树的深度,那么我们需要定义一个求树的深度的函数,因为是递归,所以按照递归三部曲(函数参数及返回值、递归终止条件、单层递归的逻辑):
函数参数及返回值:因为要得到树的深度,所以函数参数肯定包含一个TreeNode节点指针,还有一个int类型的参数depth作为当前节点的深度,好像返回值没什么好返回的;

递归终止条件:访问到空节点时就开始返回;

单层递归的逻辑:首先,进入一个节点,该节点的深度也传进来了,肯定要和当前最大深度(我们作为一个全局变量把最大深度存起来)比较,取其中较大值作为当前最大深度;然后,开始进入该节点的左孩子节点,右孩子节点;

递归代码1(求深度)
class Solution {
    int maxdep=0;
public:
    void getDepth(TreeNode* node, int depth){
        maxdep=(depth>maxdep)?depth:maxdep;
        if(node->left){
            getDepth(node->left, depth+1);
        }
        if(node->right){
            getDepth(node->right, depth+1);
        }
    }
    int maxDepth(TreeNode* root) {
        if(root==nullptr) return 0;
        getDepth(root, 1);
        return maxdep;
    }
};
递归解法2(求高度)

求高度用后序遍历,还是按递归三部曲来分析:
函数参数及返回值:首先,和求深度时一样,肯定要传入一个TreeNode节点;与求深度不同的一点是,求深度时我们还需要传入一个depth,因为求深度使用的是前序遍历,先遍历当前节点,得到当前节点的深度,此时并不能返回,还需再遍历当前节点的左右孩子节点,而遍历左右孩子节点时是需要有父节点的深度的,无法用返回值传,只能用参数传了;而求高度时不需要额外传入height参数,因为求高度使用的是后序遍历,先遍历左右孩子节点得到左右孩子节点的高度的返回值,将返回值传入本节点得到本节点的高度,然后当前函数就返回了,所以直接用返回值就可以传height参数。

递归终止条件:访问到空节点时就返回;

单层递归的逻辑:访问到空节点时,肯定返回0,表示空节点的高度为0;先递归访问得到当前节点的左、右孩子节点的高度,取两个高度的最大值+1作为当前节点的高度,并返回。

递归代码2(求高度)
int getHeight(TreeNode* node){
        if(node==nullptr) return 0;
        int leftHeight=getHeight(node->left);
        int rightHeight=getHeight(node->right);
        return 1+max(leftHeight, rightHeight);
    }
    int maxDepth(TreeNode* root) {
        return getHeight(root);
    }
迭代解法

迭代法求最大高度,肯定是用层序遍历了,for循环每访问一层就depth++就可以了,代码如下:

迭代代码(层序遍历)
int maxDepth(TreeNode* root) {
        if(root==nullptr) return 0;
        int depth=0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            int size=que.size();
            for(int i=0; i<size; i++){
                if(i==size-1) depth++;
                TreeNode *cur=que.front();
                que.pop();
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return depth;
    }

111.二叉树的最小深度

题目

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

思路

本来我想当然地认为,既然变成了求最小深度,那拿之前求最大深度的代码,直接将递归代码2(求高度)中的max改为min不就是求最小深度了吗?

试了一下,果然想当然了,因为如果直接改为min,会出现一种情况,一个节点的左孩子为空,右孩子不为空,那么该节点不是叶节点,求高度不能按这个节点算,可是直接改为min的话就变成了按这个节点算高度,导致用例2中最小高度求得是1,显然是错误的。

因此,只能将左孩子、右孩子中有一方为空的情况区分出来,一方为空的话就接着求另一方的高度,如果两方都不为空再用1+min(getHeight(node->left), getHeight(node->right))求当前节点的最小高度。

当然,本题使用递归求深度也可以,只需要访问本节点时,判断一下该节点是否为叶子节点,若为叶子节点,由原先的将当前深度与最大深度的较大值赋给最大深度改为:将当前深度与最小深度的较小值赋给最小深度,就可以了。

最后,迭代法仍然使用层序遍历,过于简单不再赘述。

代码

递归(求高度)
int getHeight(TreeNode* node){
        if(node==nullptr) return 0;
        if(node->left==nullptr&&node->right!=nullptr){
            return 1+getHeight(node->right);
        }else if(node->left!=nullptr&&node->right==nullptr){
            return 1+getHeight(node->left);
        }else{
            return 1+min(getHeight(node->left), getHeight(node->right));
        }
    }
    int minDepth(TreeNode* root) {
        return getHeight(root);
    }
递归(求深度)
class Solution {
private:
    int result;
    void getdepth(TreeNode* node, int depth) {
        // 函数递归终止条件
        if (node == nullptr) {
            return;
        }
        // 中,处理逻辑:判断是不是叶子结点
        if (node -> left == nullptr && node->right == nullptr) {
            result = min(result, depth);
        }
        if (node->left) { // 左
            getdepth(node->left, depth + 1);
        }
        if (node->right) { // 右
            getdepth(node->right, depth + 1);
        }
        return ;
    }
public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) {
            return 0;
        }
        result = INT_MAX;
        getdepth(root, 1);
        return result;
    }
};
迭代(层序遍历)
int minDepth(TreeNode* root) {
        if(root==NULL) return 0;
        int depth=0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            int size=que.size();
            for(int i=0; i<size; i++){
                TreeNode *tempNode=que.front();
                que.pop();
                if(tempNode->left==NULL&&tempNode->right==NULL){
                    return ++depth;
                }
                if(tempNode->left) que.push(tempNode->left);
                if(tempNode->right) que.push(tempNode->right);
            }
            depth++;
        }
        return 0;
    }

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

题目

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

思路

对于普通二叉树,三种遍历都可以直接统计出节点个数,但是题中已经说了这是完全二叉树,那肯定不能按常规的遍历来统计节点个数(面试时按常规的统计估计会直接G)。完全二叉树有个特殊的情况就是“满二叉树”,对于高度为n的满二叉树,节点个数就是“2^n-1”。

对于完全二叉树,可以看作由好几部分的“满二叉树组成”,而判断各个部分是不是“满二叉树”有个简单的办法,就是从当前部分的根节点出发,向左遍历到底统计出深度,向右遍历到底统计出深度,若左右深度相同,则该部分是满二叉树,否则,该部分不是满二叉树,需要继续细分。

有了上面这些知识后,我们开始递归三部曲:
函数参数与返回值:按照上面的思路,我们应该采用后序遍历,因为需要从底向上计算(只有这样才能保证计算的每部分都是满二叉树),显然参数只需要传入一个TreeNode节点,返回值为以TreeNode节点为根节点的该部分的节点个数。
递归终止条件:首先,遇到空节点肯定返回0,然后,就需要按照满二叉树的判断(该判断只针对完全二叉树有效)了,若判断该部分为满二叉树,直接利用公式2^n-1计算出该部分的节点个数,并返回;
单层递归的逻辑:若该部分不是满二叉树,则将该部分细分为左右两棵子树,继续递归求节点个数。

代码

int countNodes(TreeNode* root) {
        if(root==nullptr) return 0;
        int leftDepth=1, rightDepth=1;
        TreeNode *leftNode=root->left;
        TreeNode *rightNode=root->right;
        while(leftNode){
            leftDepth++;
            leftNode=leftNode->left;
        }
        while(rightNode){
            rightDepth++;
            rightNode=rightNode->right;
        }
        if(leftDepth==rightDepth){
            return(1<<leftDepth)-1;  //2^n-1
        }
        return countNodes(root->left)+countNodes(root->right)+1;

今天好累,就只打一天的卡吧,溜了溜了。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值