代码随想录算法训练营第20天|LeetCode104.二叉树的最大深度、LeetCode111.二叉树的最小深度、LeetCode222.完全二叉树的节点个数

文章讲述了如何使用递归和迭代方法解决LeetCode中的三个问题:计算二叉树的最大深度、最小深度以及完全二叉树的节点个数,通过实例展示了层序遍历和后续遍历的解决方案。
摘要由CSDN通过智能技术生成

代码随想录算法训练营第20天|LeetCode104.二叉树的最大深度、LeetCode111.二叉树的最小深度、LeetCode222.完全二叉树的节点个数

1.LeetCode104.二叉树的最大深度

104. 二叉树的最大深度 - 力扣(LeetCode)

代码随想录 (programmercarl.com)

这道题在学习层序遍历的时候做过了(是怒刷十道层序遍历题目中的其中之一),当时用的是迭代法,今天用递归法做一下。

迭代法

class Solution {
public:
    int maxDepth(TreeNode* root) {
        //法1 层序遍历迭代法
        int res=0;
        queue<TreeNode*> que;
        if(root == NULL)
            return res;
        que.push(root);
        while(!que.empty()){
            //这一层有几个结点
            int size = que.size();
            for(int i=0;i<size;i++){//注意这里用前面得到的size而不是que.size(),que.size()实时变化
                TreeNode* front = que.front();
                que.pop();
                if(front->left)
                    que.push(front->left);
                if(front->right)
                    que.push(front->right);
            }
            res++;
        }
        return res;
    }
};

递归法

可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。

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

而根节点的高度就是二叉树的最大深度

后续遍历(左右中)计算树的高度
  1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。
  2. 确定终止条件:如果为空节点的话,就返回0,表示高度为0。
  3. 确定单层递归的逻辑:先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。

代码

class Solution {
public:
    int maxDepth(TreeNode* root) {
        //法2 后续遍历递归法
        if(root == NULL)
            return 0;
        return max(maxDepth(root->left), maxDepth(root->right) )+1;
    }
};
前序遍历

充分表现出求深度回溯的过程

这个代码其实感觉相较于后序遍历和迭代的方法会更难理解。

class solution {
public:
    int result;
    void getdepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // 中

        if (node->left == NULL && node->right == NULL) return ;

        if (node->left) { // 左
            depth++;    // 深度+1
            getdepth(node->left, depth);
            depth--;    // 回溯,深度-1
        }
        if (node->right) { // 右
            depth++;    // 深度+1
            getdepth(node->right, depth);
            depth--;    // 回溯,深度-1
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == NULL) return result;
        getdepth(root, 1);
        return result;
    }
};

2.LeetCode111.二叉树的最小深度

111. 二叉树的最小深度 - 力扣(LeetCode)

代码随想录 (programmercarl.com)

之前在层序遍历的时候做过这道题。

迭代法

class Solution {
public:
    int minDepth(TreeNode* root) {
        int res=0;
        queue<TreeNode*> que;
        if(root == NULL)
            return res;
        que.push(root);
        bool flag=false;
        while(!que.empty()){
            //这一层有几个结点
            int size = que.size();
            res++;
            for(int i=0;i<size;i++){//注意这里用前面得到的size而不是que.size(),que.size()实时变化
                TreeNode* front = que.front();
                que.pop();
                // cout<<(front->left==front->right==NULL)<<endl;
                if(front->left == front->right){
                    cout<<"all empty"<<endl;
                    flag = true;
                    break;
                }
                if(front->left)
                    que.push(front->left);
                if(front->right)
                    que.push(front->right);
            }
            if(flag)
                break;
        }
        return res;
    }
};

递归法

后序遍历

三部曲

  1. 确定递归函数的参数和返回值

参数为要传入的二叉树根节点,返回的是int类型的深度。

  1. 确定终止条件

终止条件也是遇到空节点返回0,表示当前节点的高度为0。

  1. 确定单层递归的逻辑

与求最大深度不同,容易犯错:

int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int result = 1 + min(leftDepth, rightDepth);
return result;

上面代码会导致“没有左孩子的分支为最小深度”

111.二叉树的最小深度

因此,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。

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;

完整的精简的代码:

犯错:

  • 最后都为空/不空不用再写if判断,否则会报没有返回值的错
  • 都为空/不空忘记+1
class Solution {
public:
    int minDepth(TreeNode* root) {
        if (root == NULL) return 0;
      	// 有且仅有1个为空
        if (root->left == NULL && root->right != NULL) {
            return 1 + minDepth(root->right);
        }
        if (root->left != NULL && root->right == NULL) {
            return 1 + minDepth(root->left);
        }
      	//都不为空/都空
        return 1 + min(minDepth(root->left), minDepth(root->right));
    }
};

3、LeetCode222.完全二叉树的节点个数

222. 完全二叉树的节点个数 - 力扣(LeetCode)

代码随想录 (programmercarl.com)

普通二叉树

第一想法:

  • 层序遍历然后数数
  • 或者递归遍历,引用传递个数

但只考虑了普通二叉树,而没有利用完全二叉树的性质。

递归代码:

一遍过!

class Solution {
public:
    void preorder(TreeNode* root, int &cnt){
        if(root==NULL)
            return;
        else
            cnt++;
        preorder(root->left, cnt);
        preorder(root->right, cnt);
    }
    int countNodes(TreeNode* root) {
        int cnt=0;
        preorder(root,cnt);
        return cnt;
    }
};

迭代法代码去看层序遍历的笔记。

完全二叉树

在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。

下面是满二叉树。

img

下面不是满二叉树

img

下面不是完全二叉树

img

思路:

如果左右子树不是满二叉树,则递归,知道找到满二叉树。叶子节点总是满二叉树。

实际上是后续遍历-见代码

代码:

**犯错:**leftDepth从0开始,是满二叉树时忘记+1,忘记加上根节点。

class Solution {
public:
    int countNodes(TreeNode* root) {
        //法2 利用完全二叉树的性质
        if(root == NULL)
            return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftDepth = 0;
        int rightDepth = 0;
        // 分别向左、向右遍历
        while(left){
            leftDepth++;
            left = left->left;
        }
        while(right){
            rightDepth++;
            right = right->right;
        }
        // 是满二叉树
        if(leftDepth == rightDepth)
            return (1<<leftDepth+1)-1;
        // 不是满二叉树
        return countNodes(root->left)+countNodes(root->right)+1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值