【代码随想录训练营第42期 Day15打卡 二叉树Part3-LeetCode 222.完全二叉树的节点个数 110. 平衡二叉树 257. 二叉树的所有路径 404. 左叶子之和

目录

一、做题心得

二、题目与题解

题目一:222.完全二叉树的节点个数 

题目链接

题解1:递归

题解2:BFS(直接套模板)

题目二:110. 平衡二叉树 

题目链接

题解:递归(DFS)

题目三:257. 二叉树的所有路径

题目链接

题解:DFS前序遍历(递归)

题目四:404. 左叶子之和

题目链接

题解:BFS(套模板)

三、小结


一、做题心得

今天是代码随想录打卡的第15天,学习的是二叉树部分的part3。主要也是递归思想和BFS,DFS遍历的应用,总体而言难度不大,但是递归仍然不容易想到如何实现。今天的题也分别提到了完全二叉树,平衡二叉树以及叶子节点等知识点,恰好也作为巩固来练习。

话不多说,直接开始今天的内容。

二、题目与题解

题目一:222.完全二叉树的节点个数 

题目链接

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

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

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

示例 1:

输入:root = [1,2,3,4,5,6]
输出:6

示例 2:

输入:root = []
输出:0

示例 3:

输入:root = [1]
输出:1

提示:

  • 树中节点的数目范围是[0, 5 * 104]
  • 0 <= Node.val <= 5 * 104
  • 题目数据保证输入的树是 完全二叉树
题解1:递归

这个题我们很容易想到直接递归的方式,就当做一个普通二叉树来看,直接得到一颗任意二叉树的节点数,方法上讲和昨天打卡的二叉树的最大深度差不多。

二叉树节点数 = 左子树节点数 + 右子树节点数 + 1(即根节点)

代码如下:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr)    return 0;
        return countNodes(root->left) + countNodes(root->right) + 1;    //左子树节点数+右子树节点数+1(根节点)
    }
};
题解2:BFS(直接套模板)

前两天其实就做了不少用BFS进行层序遍历从而解决二叉树问题的了,这里就不做过多解释,直接套用之前层序遍历的模板,挨个遍历树的全部节点。

代码如下:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr)    return 0;
        queue<TreeNode*> q;
        int ans = 0;
        q.push(root);
        while (!q.empty()) {
            int size = q.size();
            ans += size;
            for (int i = 0; i < size; i++) {
                TreeNode* node = q.front();
                q.pop();
                if(node->left)     q.push(node->left);
                if(node->right)    q.push(node->right); 
            }
        }
        return ans;
    }
};

这道题其实还有二分的解法,相对而言更高效,这里我主要想说的是对于任意一颗二叉树的通法,所有这种方法就不过多介绍了。

题目二:110. 平衡二叉树 

题目链接

110. 平衡二叉树 - 力扣(LeetCode)

给定一个二叉树,判断它是否是 

平衡二叉树

  

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [0, 5000] 内
  • -104 <= Node.val <= 104
题解:递归(DFS)

首先说下平衡二叉树的定义:

平衡二叉树是指该树所有节点的左右子树的深度相差不超过1的二叉树。(注意是所有节点)

然后我们看到这道题,判断所有节点的左右子树,自然而然就容易想到递归的解法:

递归:确保所有节点左右子树的深度相差不超过1(绝对值之差小于等于1)
确保根节点满足:abs(Depth(root->left) - Depth(root->right)) <= 1
所有节点都满足:体现在递归的实现,每次递归都会往左右子树向下遍历(isBalanced(root->left) && isBalanced(root->right))

代码如下:

class Solution {
public:
    int Depth(TreeNode* node) {     //计算某节点子树最大深度
        if (node == nullptr)    return 0;
        return max(Depth(node->left),Depth(node->right)) + 1;
    }
    bool isBalanced(TreeNode* root) {
        if (root == nullptr)    return true;
        return abs(Depth(root->left) - Depth(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);
    }
};

题目三:257. 二叉树的所有路径

题目链接

257. 二叉树的所有路径 - 力扣(LeetCode)

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

 

示例 1:

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]

示例 2:

输入:root = [1]
输出:["1"]

提示:

  • 树中节点的数目在范围 [1, 100] 内
  • -100 <= Node.val <= 100
题解:DFS前序遍历(递归)

这里用到一个函数:

to_string():将数字转化为字符串

这个题要得到二叉树的所有路径,首先就该想到的便是递归思想。

定义traversal()函数来实现添加全部路径:

1.首先将当前节点的值转换为字符串并追加到path中。

2.然后,它检查当前节点是否为叶子节点(即没有左右子节点)。

        如果是叶子节点,说明找到了一条从根到叶子的完整路径,于是将该路径添加到ans中。

        如果当前节点不是叶子节点,则递归地对左子节点和右子节点调用traversal函数,同时在path后添加"->"作为路径中节点之间的分隔符。

class Solution {
public:
    void traversal(TreeNode* cur, string path, vector<string>& ans) {
        path += to_string(cur->val);    //将当前节点的值转换为字符串并添加到当前路径的末尾      //根
        if (cur->left == nullptr && cur->right == nullptr) {    //递归终止条件:当前节点没有子节点(此时就是叶子节点)
            ans.push_back(path);        //添加路径到结果中
            return ;
        }
        if (cur->left)      traversal(cur->left, path + "->",ans);      //如果存在左子节点,递归遍历左子树,并在当前路径后添加"->"作为分隔符  
        if (cur->right)     traversal(cur->right, path + "->",ans);     //如果存在右子节点,递归遍历右子树,同样在当前路径后添加"->"作为分隔符
    }
    
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> ans;         //存放结果(路径)
        string path;        //路径
        if (root == nullptr)    return ans;
        traversal(root, path, ans);
        return ans;

    }
};

题目四:404. 左叶子之和

题目链接

404. 左叶子之和 - 力扣(LeetCode)

给定二叉树的根节点 root ,返回所有左叶子之和。

示例 1:

输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

示例 2:

输入: root = [1]
输出: 0

提示:

  • 节点数在 [1, 1000] 范围内
  • -1000 <= Node.val <= 1000

题解:BFS(套模板)

这道题也可以作为一个BFS层序遍历题来做,可以直接套之前用的层序遍历模板:【代码随想录训练营第42期 Day13打卡 二叉树的遍历-- LeetCode 144. 二叉树的前序遍历 94. 二叉树的中序遍历 145. 二叉树的后序遍历 102. 二叉树的层序遍历-CSDN博客

这里要注意的就是定义函数IsLeaf(),用来判断当前节点是否为叶子节点(左右节点都没有)。

然后就是通过层序遍历逐个遍历找到左叶子节点即可。

代码如下:

class Solution {
public:
    bool IsLeaf(TreeNode* node) {       //定义IsLeaf()函数判断某节点是否为叶子节点(左右子节点都没有)
        return !node->left && !node->right;
    }

    int sumOfLeftLeaves(TreeNode* root) {
        queue<TreeNode*> q;
        int ans = 0;
        if (root == nullptr)    return 0;
        q.push(root);
        while (!q.empty()) {            //经典模板
            TreeNode* node = q.front();
            q.pop();
            if (node->left) {
                if (IsLeaf(node->left)) {       //(当前节点的)左子节点为叶子节点(即没子节点的节点)
                    ans += node->left->val;
                }
                else {
                    q.push(node->left);     //如果左子节点不是叶子节点,则将其加入队列以便后续处理  
                }
            }
            if (node->right) {
                if (!IsLeaf(node->right)) {    //node->right有子节点时
                    q.push(node->right);    //将其加入队列以便后续处理  
                }
            }
        }
            return ans;
    }
};

三、小结

今天的题目整体难度不大,但帮助我们对于递归的理解还是很重要。个人感觉自己对递归还是理解的比较浅,后边还会继续学习回溯在递归中的应用与作用。好了,今天的打卡到此结束。最后,我是算法小白,但也希望终有所获。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值