代码随想录算法训练营第十四天 | 110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

代码随想录算法训练营第十四天 | 110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

1 LeetCode 110.平衡二叉树

题目链接:https://leetcode.cn/problems/balanced-binary-tree/

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例 1:

img

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

示例 2:

img

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

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [0, 5000]
  • -104 <= Node.val <= 104

作为408选手,我想说本题也是408未来可能会涉及的题目,因此我们也必须注意一下,对于平衡二叉树的定义想必大家并不陌生(对于一棵二叉树,如果任何一个节点的左子树和右子树高度之差的绝对值不超过1,则这是一棵平衡二叉树,并且规定空平衡二叉树的高度为0,且空二叉树也是平衡的),知道平衡二叉树的定义之后,我们就很清楚我们需要分别求出节点的左子树和右子树的高度,然后求其差的绝对值是否超过1来判断,如果满足,则返回给上一层节点,以此类推,如果不满足就可以直接返回不是平衡二叉树,很明显我们需要使用后序遍历的方法来解决这道题目。

(1)Python版本代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        def checkBalance(node): 
            if not node:    # 空平衡二叉树
                return 0    
            left_height = checkBalance(node.left)   # 左子树高度
            right_height = checkBalance(node.right)     # 右子树高度
            if left_height == -1 or right_height == -1 or abs(left_height - right_height) > 1:  # 不符合平衡二叉树定义
                return -1   # -1 代表不平衡
            return max(left_height, right_height) + 1      # 返回最大高度

        return checkBalance(root) != -1

checkBalance函数用于递归地检查每个节点,如果遇到任何不平衡的子树,它会立即返回-1,这样一旦发现不平衡,递归就会提前终止,并通过连锁反应快速传递不平衡的状态回到根节点,如果树是平衡的,checkBalance会返回树的实际高度,而不是-1,因此最终的isBalanced调用检查checkBalance(root)的返回值是否不等于-1来确定整棵树是否平衡。

(2)C++版本代码

#include <iostream>
#include <algorithm>

class TreeNode {
public:
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    bool isBalanced(TreeNode* root) {
        return checkBalance(root) != -1;
    }

private:
    int checkBalance(TreeNode* node) {
        if (!node) { // 空树是平衡的
            return 0;
        }
        int leftHeight = checkBalance(node->left);
        if (leftHeight == -1) { // 左子树不平衡
            return -1;
        }
        int rightHeight = checkBalance(node->right);
        if (rightHeight == -1) { // 右子树不平衡
            return -1;
        }
        if (abs(leftHeight - rightHeight) > 1) { // 当前节点不平衡
            return -1;
        }
        return std::max(leftHeight, rightHeight) + 1; // 返回当前节点为根的树的高度
    }
};

2 LeetCode 257.二叉树的所有路径

题目链接:https://www.heywhale.com/home/activity/recent

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

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

示例 1:

img

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

示例 2:

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

提示:

  • 树中节点的数目在范围 [1, 100]
  • -100 <= Node.val <= 100

本题需要涉及收集递归过程中的路径,因此会涉及到回溯,我们从根节点开始,每次遍历到一个节点时,都会检查该节点是否是叶子节点(即没有子节点),如果是叶子节点,就将从根节点到该叶子节点的路径添加到结果列表中,遍历过程中,通过字符串拼接的方式构建路径,递归的过程保证了能够访问到树的每一个节点,从而找出所有可能的路径。

(1)Python版本代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        result = []    # 用于存储所有路径的结果列表
        if not root:    # 如果根节点为空,则直接返回空的结果列表
            return result
        def dfs(node, path):    # 定义深度优先搜索函数,node为当前访问的节点,path为从根节点到当前节点的路径
            if not node.left and not node.right:    # 如果当前节点是叶子节点,将路径添加到结果列表中
                result.append(path)
            if node.left:   # 如果存在左子节点,递归调用dfs函数,路径加上"->"和左子节点的值
                dfs(node.left, path + "->" + str(node.left.val))
            if node.right:  # 如果存在右子节点,递归调用dfs函数,路径加上"->"和右子节点的值
                dfs(node.right, path + "->" + str(node.right.val))
        dfs(root, str(root.val))    # 从根节点开始递归搜索,初始路径为根节点的值
        return result   # 返回所有从根节点到叶子节点的路径

(2)C++版本代码

/**
 * 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) {}
 * };
 */
 
#include <vector>
#include <string>
using namespace std;

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result; // 用于存储所有路径的结果列表
        if (!root) return result; // 如果根节点为空,则直接返回空的结果列表
        
        // 定义深度优先搜索函数,node为当前访问的节点,path为从根节点到当前节点的路径
        auto dfs = [&](TreeNode* node, string path) {
            if (!node->left && !node->right) { // 如果当前节点是叶子节点,将路径添加到结果列表中
                result.push_back(path);
            }
            if (node->left) { // 如果存在左子节点,递归调用dfs函数,路径加上"->"和左子节点的值
                dfs(node->left, path + "->" + to_string(node->left->val));
            }
            if (node->right) { // 如果存在右子节点,递归调用dfs函数,路径加上"->"和右子节点的值
                dfs(node->right, path + "->" + to_string(node->right->val));
            }
        };
        
        dfs(root, to_string(root->val)); // 从根节点开始递归搜索,初始路径为根节点的值
        return result; // 返回所有从根节点到叶子节点的路径
    }
};

3 LeetCode 404.左叶子之和

题目链接:https://leetcode.cn/problems/sum-of-left-leaves/description/

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

示例 1:

img

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

示例 2:

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

提示:

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

这道题目力扣上面是没有详细介绍什么是左叶子,但是根据题目我们也不难看出,左叶子的定义就是某节点的左孩子存在,且其左孩子为叶子节点,那么此节点的左孩子就是左叶子。

需要注意的是,我们不能从当前节点来判断它是不是左叶子,因为左叶子本身也是叶子节点,但不能保证他是其父节点的左孩子,因此我们就需要从其父节点进行判断,判断的依据也就当左孩子的定义,我们需要用后序遍历的来进行遍历判断。

接下来我们按照卡哥的递归三部曲开始分析。

  • 确定递归函数的参数和返回值:这个很简单,我们只需要传入根节点,返回值就是数值和。
  • 确定终止条件:如果遍历到空节点,那左叶子值一定为0,我们还需要注意的是,如果当前节点不为空,但是其左右孩子不存在,我们也需要返回左叶子值为0.
  • 确定单层递归的逻辑:那就是按照左叶子的定义写即可,那就是当遍历到左叶子时就记数,然后不断递归求左子树的左叶子之和和右子树左叶子之和,最后相加。

现在我们开始写代码复现我们的思路来证明它是正确的。

(1)Python版本代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        if not root or (not root.left and not root.right):
            return 0
        leftNums = self.sumOfLeftLeaves(root.left)
        if root.left and not root.left.left and not root.left.right:
            leftNums += root.left.val
        rightNums = self.sumOfLeftLeaves(root.right)
        return leftNums + rightNums

(2)C++版本代码

/**
 * 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 sumOfLeftLeaves(TreeNode* root) {
        if (!root || (!root->left && !root->right)) {
            return 0;
        }
        int leftNums = sumOfLeftLeaves(root->left);
        if (root->left && !root->left->left && !root->left->right) {
            leftNums += root->left->val;
        }
        int rightNums = sumOfLeftLeaves(root->right);
        return leftNums + rightNums;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-北天-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值