重拾C++之菜鸟刷算法第8篇---二叉树(中)

五、对称二叉树

题目

给你一个二叉树的根节点 root , 检查它是否轴对称。

101. 对称二叉树 - 力扣(LeetCode)

题解 ------ 递归法

  • 递归函数的参数设置:左右节点之间的比较,这里并不是左右子树的比较哦。
  • 迭代停止条件
    • 左节点为空,右节点不为空 返回false
    • 左节点不为空,右节点为空 返回false
    • 左节点为空,右节点也为空 返回true
    • 左节点不为空,右节点也不为空,则需要判断节点相应的值
      • 值不相等 返回false
  • 单次递归过程(值相等的情况,则进入单层递归情况)
    • 比较外侧(left->left, right->right)
    • 比较内侧(left->right, right->left)
    • 如果内外侧都对称,则返回true
C++ 复制代码
class Solution {
public:
    bool isTheSame(TreeNode* left, TreeNode* right){
        // 迭代参数的设置
        // 左节点不为空 右节点为空
        if(left != nullptr && right == nullptr) return false;
        // 左节点为空 右节点不为空
        else if(left == nullptr && right != nullptr) return false;
        // 左节点为空 右节点为空
        else if(left == nullptr && right == nullptr) return true;
        // 左节点值不等于右节点值
        else if(left->val != right->val) return false;

        // 左节点值等于右节点值,进入单层递归
        // 比较外侧
        bool outside = isTheSame(left->left, right->right);
        // 比较内侧
        bool inside = isTheSame(left->right, right->left);
        // 左右对称返回true
        bool bothSide = outside && inside;
        return bothSide;


    }
    bool isSymmetric(TreeNode* root) {
        if(root == nullptr) return true;
        bool result = isTheSame(root->left, root->right);
        return result;
    }
};

六、二叉树的最大深度

题目

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

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

题解1 -- 递归法

C++ 复制代码
class Solution {
public:
    int getDepth(TreeNode* node){
        if(node == nullptr) return 0;
        int left = getDepth(node->left);
        int right = getDepth(node->right);
        int depth = 1 + max(left, right);
        return depth;
    }
    int maxDepth(TreeNode* root) {
        return getDepth(root);
    }
};

题解2 -- 层次遍历

C++ 复制代码
class Solution {
public:
    int maxDepth(TreeNode* root) {
        queue<TreeNode*> q;
        int maxD = 0;
        if(root == nullptr) return maxD;
        q.push(root);
        while(!q.empty()){
            int size = q.size();
            vector<int> vec;
            while(size--){
                TreeNode*tmp = q.front();
                q.pop();
                vec.push_back(tmp->val);
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
            }
            maxD++;
        }
        return maxD;
    }
};

七、二叉树的最小深度

题目

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

**说明:**叶子节点是指没有子节点的节点。

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

题解

C++ 复制代码
class Solution {
public:
    int getMinDepth(TreeNode* node){
        if(node == nullptr) return 0;
        // 根据题目的定义,最小深度是从根节点到某个叶子节点,而叶子节点则是左右节点都为空
        if(node->left == nullptr && node->right != nullptr) return getMinDepth(node->right) + 1;
        else if(node->left != nullptr && node->right == nullptr) return getMinDepth(node->left) + 1;
        return 1 + min(getMinDepth(node->left), getMinDepth(node->right));
    }
    int minDepth(TreeNode* root) {
        return getMinDepth(root);
    }
};

八、完全二叉树的节点个数

题目

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

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

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

题解

C++ 复制代码
class Solution {
public:
    int countNodes(TreeNode* root) {
        queue<TreeNode*> q;
        int count = 0;
        if(root == nullptr) return count;
        q.push(root);
        while(!q.empty()){
            int size = q.size();
            vector<int> vec;
            while(size--){
                TreeNode* node = q.front();
                q.pop();
                vec.push_back(node->val);
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);
            }
            count += vec.size();
        }
        return count;
    }
};

九、平衡二叉树

题目

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

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

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

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

题解

C++ 复制代码
class Solution {
public:
    int getResult(TreeNode* node){
    	// 停止条件
        if(node == nullptr) return 0;
        // left
        int left = getResult(node->left);
        if(left == -1) return -1;
        // right
        int right = getResult(node->right);
        if(right == -1) return -1;
        // middle
        if(abs(left - right) > 1) return -1;
        else return 1 + max(left, right);
    }
    bool isBalanced(TreeNode* root) {
        return getResult(root) != -1? true: false;
    }
};

十、二叉树的所有路径

题目

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

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

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

题解

回溯机制是一种在递归算法中经常使用的技术,它确保在递归过程中对数据结构的修改能够被正确撤销,使得每次递归完成后数据结构回到原始状态。在这段代码中,回溯主要通过path.pop_back()来实现。

  1. path.push_back(cur->val) 在递归遍历二叉树的过程中,将当前节点的值加入路径(path)中,表示当前路径经过这个节点。
  2. 回溯的目的: 当遍历完当前节点的左子树和右子树后,需要回到上一层节点,撤销对路径的修改,以确保在递归的不同路径中不发生干扰。
  3. path.pop_back() 这行代码实现了回溯。它的作用是将path中最后一个元素弹出,即撤销对路径的最后一次修改。
    • 在处理左子树之后,表示回溯到上一层,撤销对左子树的修改。
    • 在处理右子树之后,表示回溯到上一层,撤销对右子树的修改。

更加形象的说明

想象你置身于一座迷宫中,这座迷宫是一棵二叉树的结构。你的目标是找到通向宝藏(叶子节点)的所有路径。让我们以这个代码为例,形象描述回溯的过程:

  1. 起点:
    • 你站在树的根节点,开始探索路径。
  2. 沿左子树探索:
    • 你选择往左走,表示遍历当前节点的左子树。
    • 沿途你记录下经过的节点值,就像在迷宫中留下标记。
  3. 到达叶子节点:
    • 当你到达一个叶子节点,表示你找到了一条通向宝藏的路径。
    • 你将这条路径记录下来,包括所有经过的节点值。
  4. 回溯左子树:
    • 然后你需要回到上一层,撤销往左走的决策,就像在迷宫中返回到分叉路口。
    • 在回溯的过程中,你擦除了最后一个标记,表示回到了上一层节点。
  5. 沿右子树探索:
    • 接着,你决定往右走,继续探索其他可能的路径。
    • 类似地,在途中你又记录下了经过的节点值。
  6. 到达叶子节点:
    • 当你再次到达叶子节点,表示找到了另一条通向宝藏的路径。
    • 你将这条路径同样记录下来。
  7. 回溯右子树:
    • 回溯的过程再次发生,你擦除了最后一个标记,回到了上一层节点。
  8. 完成探索:
    • 你继续这个探索和回溯的过程,直到你遍历了整棵二叉树。
    • 最终,你找到了所有通向宝藏的路径。
C++ 复制代码
class Solution {
public:
    void getResult(TreeNode* node, vector<TreeNode*> &path, vector<string> &result){
        // 表示当前路径经过这个节点
        path.push_back(node);
        // 遇到了叶子节点,保存到result
        if(node->left == nullptr && node->right == nullptr){
            string tmp;
            for(int i = 0; i < path.size() - 1; i++){
                tmp += to_string(path[i]->val);
                tmp += "->";
            }
            tmp += to_string(path[path.size() - 1]->val);
            result.push_back(tmp);
        }
        // 左节点不为空
        if(node->left){
            getResult(node->left, path, result);
            // pop出当前这个点, 不打扰下一次递归路径
            path.pop_back();
        }
        if(node->right){
            getResult(node->right, path, result);
            path.pop_back();
        }
    }
    
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<TreeNode*> path;
        if(root == nullptr) return result;
        getResult(root, path, result);
        return result;
    }
};
相关推荐
LeonNo111 分钟前
golang,多个proxy拉包的处理逻辑
开发语言·后端·golang
唐棣棣11 分钟前
C++:单例模式
开发语言·c++·单例模式
@Java小牛马17 分钟前
排序算法原理及其实现
java·数据结构·算法·排序算法
xiaocaibao77719 分钟前
Bash语言的语法
开发语言·后端·golang
小怪瘦7924 分钟前
JS实现Table表格数据跑马灯效果
开发语言·javascript·信息可视化
智多星00127 分钟前
c++Qt登录页面设计
开发语言·c++·qt
Tfly__32 分钟前
ubuntu 18.04安装GCOPTER(最新)
linux·c++·ubuntu·github·ros·无人机·运动规划
KeyPan40 分钟前
【视觉惯性SLAM:十一、ORB-SLAM2:跟踪线程】
人工智能·数码相机·算法·机器学习·计算机视觉
吾与谁归in43 分钟前
【C#学习——特性】
开发语言·c#
code monkey.44 分钟前
【探寻C++之旅】第一章:C++入门
开发语言·c++