第六章 二叉树part03

平衡二叉树

题目描述

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

示例 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

解题思路

  1. 通过递归计算每个节点左右子树的高度,并检查它们的高度差是否大于1,以此判断树是否平衡。
  2. 如果发现任何子树不平衡(即高度差大于1),则立即返回-1,表示整个树不平衡。
  3. 如果所有节点都平衡,则返回树的实际高度,最终通过检查根节点的高度是否为-1来确定整个树是否平衡。

代码实现

测试地址:https://leetcode.cn/problems/balanced-binary-tree/

class Solution {
public:
    // 计算二叉树节点的高度,如果发现不平衡则返回-1
    int getHeight(TreeNode *node) {
        if (node == nullptr) { // 如果节点为空,高度为0
            return 0;
        }
        int leftHeight = getHeight(node->left); // 递归计算左子树的高度
        if (leftHeight == -1) // 如果左子树不平衡,直接返回-1
            return -1;
        int rightHeight = getHeight(node->right); // 递归计算右子树的高度
        if(rightHeight == -1) // 如果右子树不平衡,直接返回-1
            return -1;
        // 如果左右子树高度差大于1,则树不平衡,返回-1;否则返回当前节点的高度
        return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + std::max(leftHeight,rightHeight);
    }

    // 判断二叉树是否平衡
    bool isBalanced(TreeNode *root) { 
        return getHeight(root) == -1 ? false : true; // 如果根节点的高度返回-1,则树不平衡,否则平衡
    }
};

二叉树的所有路径

题目描述

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

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

示例 1:

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

示例 2:

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

解题思路

递归遍历二叉树,记录从根节点到每个叶子节点的路径,并将这些路径转换为字符串格式存储在结果中。在遍历过程中,使用一个向量 path 来存储当前路径的节点值,当到达叶子节点时,将路径转换为字符串做相关处理后添加到结果向量 result 中。每次递归返回时,从 path 中移除当前节点,以便回溯到上一路径继续探索其他分支。

代码实现

测试地址:https://leetcode.cn/problems/binary-tree-paths/

class Solution {
private:
    // 递归函数,用于遍历树并记录路径
    void travelsal(TreeNode *cur, vector<int> &path, vector<string> &result) {
        // 将当前节点的值添加到路径中
        path.push_back(cur->val);
        // 如果当前节点是叶子节点,则将路径转换为字符串并添加到结果中
        if (cur->left == nullptr && cur->right == nullptr) {
            string subPath;
            for (int i = 0; i < path.size() - 1; i++) {
                subPath += to_string(path[i]);
                subPath += "->";
            }
            subPath += to_string(path[path.size() - 1]);
            result.push_back(subPath);
            return;
        }
        // 如果存在左子树,则递归遍历左子树,并在返回后从路径中移除当前节点
        if (cur->left) {
            travelsal(cur->left, path, result);
            path.pop_back();
        }
        // 如果存在右子树,则递归遍历右子树,并在返回后从路径中移除当前节点
        if (cur->right) {
            travelsal(cur->right, path, result);
            path.pop_back();
        }
    }

public:
    // 主函数,用于初始化路径和结果,并调用遍历函数
    vector<string> binaryTreePaths(TreeNode *root) {
        vector<string> result; // 存储所有路径字符串的结果
        vector<int> path; // 存储当前路径的节点值
        if (root == nullptr)
            return result; // 如果根节点为空,直接返回空结果
        travelsal(root, path, result); // 从根节点开始遍历树
        return result; // 返回所有路径字符串
    }
};

左叶子之和

题目描述

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

示例 1:

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

示例 2:

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

解题思路

递归法:

递归遍历二叉树,查找并累加所有左叶子节点的值。在遍历过程中,如果当前节点的左子节点是叶子节点(即没有左右子节点),则将其值计入总和。通过递归调用,分别计算左子树和右子树中左叶子节点的值,并将两者相加得到最终结果。

迭代法:

使用栈来迭代遍历二叉树,查找并累加所有左叶子节点的值。在遍历过程中,如果当前节点的左子节点是叶子节点(即没有左右子节点),则将其值加到结果中。通过栈的先进后出特性,确保了树的深度优先遍历,同时正确处理了左叶子节点的值累加。

代码实现

测试地址:https://leetcode.cn/problems/sum-of-left-leaves/

递归法:

class Solution {
public:
    // 计算二叉树中所有左叶子节点的值之和
    int sumOfLeftLeaves(TreeNode *root) {
        // 如果根节点为空,返回0
        if (root == nullptr)
            return 0;
        // 如果根节点没有左右子节点,返回0
        if (root->left == nullptr && root->right == nullptr)
            return 0;

        // 递归计算左子树中左叶子节点的值之和
        int leftValue = sumOfLeftLeaves(root->left);
        // 如果左子节点是叶子节点,则其值应被计入总和
        if (root->left && !root->left->left && !root->left->right) {
            leftValue = root->left->val;
        }
        // 递归计算右子树中左叶子节点的值之和
        int rightValue = sumOfLeftLeaves(root->right);

        // 计算左子树和右子树中左叶子节点值之和
        int sum = leftValue + rightValue;
        return sum;
    }
};

迭代法:

class Solution {
public:
    // 计算二叉树中所有左叶子节点的值之和
    int sumOfLeftLeaves(TreeNode* root) {
        // 使用栈来辅助进行迭代遍历
        stack<TreeNode*> st;
        // 如果根节点为空,返回0
        if (root == NULL) return 0;
        // 将根节点压入栈中
        st.push(root);
        // 初始化结果为0
        int result = 0;
        // 当栈不为空时,循环执行以下操作
        while (!st.empty()) {
            // 取出栈顶节点
            TreeNode* node = st.top();
            st.pop();
            // 如果当前节点的左子节点是叶子节点,则将其值加到结果中
            if (node->left != NULL && node->left->left == NULL && node->left->right == NULL) {
                result += node->left->val;
            }
            // 如果当前节点有右子节点,将其压入栈中
            if (node->right) st.push(node->right);
            // 如果当前节点有左子节点,将其压入栈中
            if (node->left) st.push(node->left);
        }
        // 返回计算出的左叶子节点值之和
        return result;
    }
};

完全二叉树的节点个数

题目描述

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

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

示例 1:

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

示例 2:

输入:root = []
输出:0

示例 3:

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

解题思路

二叉树后序遍历思路

自底向上遍历二叉树的每个节点,计算左子树和右子树的节点数,并将它们与当前节点相加,从而得到整个树的节点总数。

层序遍历思路

通过队列实现层次遍历,每次处理一层的节点,并在处理过程中累加节点总数。

完全二叉树特性思路

如果左右子树的深度相同,则使用特定公式直接计算节点数;否则,递归计算左右子树的节点数并相加

代码实现

测试地址:https://leetcode.cn/problems/count-complete-tree-nodes/description/

普通二叉数的后序遍历:

lass Solution {
private:
    // 递归函数,用于计算以给定节点为根的树的节点总数
    int getNodesNum(TreeNode* cur) {
        // 如果当前节点为空,返回0
        if (cur == nullptr)
            return 0;
        // 递归计算左子树的节点数
        int leftNum = getNodesNum(cur->left);
        // 递归计算右子树的节点数
        int rightNum = getNodesNum(cur->right);
        // 计算当前树的节点数,包括当前节点
        int treeNum = leftNum + rightNum + 1;
        return treeNum; // 返回节点总数
    }

public:
    int countNodes(TreeNode* root) {
        return getNodesNum(root); // 从根节点开始计算
    }
};

极简写法

class Solution {
public:
    // 计算二叉树的节点总数
    int countNodes(TreeNode* root) {
        // 如果根节点为空,返回0
        if (root == NULL) return 0;
        // 递归计算左子树和右子树的节点数,并加上当前节点
        return 1 + countNodes(root->left) + countNodes(root->right);
    }
};

层序遍历:

class Solution {
public:
    int countNodes(TreeNode* root) {
        queue<TreeNode*> que; // 使用队列进行广度优先搜索
        if (root != nullptr)
            que.push(root); // 如果根节点不为空,将其加入队列
        int result = 0; // 用于记录节点总数
        while (!que.empty()) { // 当队列不为空时,继续遍历
            int size = que.size(); // 当前层的节点数
            for (int i = 0; i < size; i++) { // 遍历当前层的所有节点
                TreeNode* node = que.front(); // 取出队列头部的节点
                que.pop(); // 移除队列头部的节点
                result++; // 增加节点计数
                if (node->left)
                    que.push(node->left); // 如果左子节点存在,将其加入队列
                if (node->right)
                    que.push(node->right); // 如果右子节点存在,将其加入队列
            }
        }
        return result; // 返回节点总数
    }
};

完全二叉树定义的后序遍历:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) // 如果根节点为空,返回0
            return 0;
        TreeNode* left = root->left; // 获取左子节点
        TreeNode* right = root->right; // 获取右子节点
        int leftDepth = 0, rightDepth = 0; // 初始化左右子树的深度
        while (left) { // 计算左子树的深度
            left = left->left;
            leftDepth++;
        }
        while (right) { // 计算右子树的深度
            right = right->right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) { // 如果左右子树深度相同,说明是完全二叉树
            return (2 << leftDepth) - 1; // 使用公式计算完全二叉树的节点数
        }
        // 否则,递归计算左右子树的节点数并相加
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值