【LeetCode 热题 100】二叉树 系列

news2025/7/19 15:33:47

📁 104. 二叉树的最大深度

        深度就是树的高度,即只要左右子树其中有一个不为空,就继续往下递归,知道节点为空,向上返回。

int maxDepth(TreeNode* root) {
        if(root == nullptr)
            return 0;
        return max(maxDepth(root->left) , maxDepth(root->right)) + 1;
    }

📁 94. 二叉树的中序遍历

        中序遍历就是先访问左子树,再访问根节点,最后访问右子树。

class Solution {
public:
    vector<int> ans;

    vector<int> inorderTraversal(TreeNode* root) {
        dfs(root);    
        return ans;
    }

    void dfs(TreeNode* root)
    {
        if(root == nullptr)
            return ;
        dfs(root->left);
        ans.push_back(root->val);
        dfs(root->right);
    }
};

📁 226. 翻转二叉树

        对二叉树来一遍后序遍历,即先将左右子树翻转,保存反转后的左右子树的根节点,让root左右子树指针分别指向右子树,左子树。

TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr)
            return root;
        TreeNode* left = invertTree(root->left);
        TreeNode* right = invertTree(root->right);

        root->right = left;
        root->left = right;

        return root;
    }

📁 101. 对称二叉树

        求对称二叉树,我们只需要判断左右子树是否满足满足下面这些性质:1. 左右子树根节点相同;2. 左子树的右子树 = 右子树的的左子树;3. 左子树的左子树 = 右子树的右子树。

    bool isSymmetric(TreeNode* root) {
        return isSameTree(root->left , root->right);
    }

    bool isSameTree(TreeNode* t1 , TreeNode* t2)
    {
        if(t1 == nullptr && t2 == nullptr)
            return true;
        if(t1 == nullptr || t2 == nullptr)
            return false;
        if(t1->val != t2->val)
            return false;
        return isSameTree(t1->left , t2->right) && isSameTree(t1->right , t2->left);
    }

📁 543. 二叉树的直径

        以某个节点为根节点,统计做左子树的最长路径,在统计右子树的最长路径,左右子树最长路径相加就是该二叉树的直径。

        递归函数向上返回该二叉树的最长路径。

    int ans = 0;

    int diameterOfBinaryTree(TreeNode* root) {
        depth(root);

        return ans;
    }
    int depth(TreeNode* root)
    {
        if(root == nullptr)
            return 0;

        int left = depth(root->left);
        int right = depth(root->right);

        ans = max(ans , left + right);

        return max(left , right) + 1;
    }

📁 102. 二叉树的层序遍历

        我们使用队列来完成二叉树的层序遍历,利用队列 [先入先出]的特性,将每一层的节点入队列,出队列按一层节点个数出队列。

        如果出队列的每一个节点左右子树指针还有节点,在入队列,因为之前已经确定好了每一层节点个数,因此出队列时不回影响新入队列的节点。

vector<vector<int>> levelOrder(TreeNode* root) {
        if(root == nullptr)
            return vector<vector<int>>();

        vector<vector<int>> ret;            
        queue<TreeNode*> q;
        q.push(root);

        while(!q.empty())
        {
            vector<int> tmp;   //记录该层每一个节点的值
            int sz = q.size(); //记录该层的节点个数
            for(int i = 0 ; i < sz ; ++i)
            {   
                TreeNode* node = q.front();q.pop();
                
                tmp.push_back(node->val);

                if(node->left)
                    q.push(node->left);
                if(node->right)
                    q.push(node->right);
            }
            ret.push_back(tmp);
        }

        return ret;
    }

📁 108. 将有序数组转换为二叉搜索树

        二叉搜索树的特征就是,左子树所有节点的值都小于根节点的值,右子树所有节点的值都大于根节点的值;对二叉搜索树进行前序遍历得到的结果是一个有序数组。

        对于本题,我们就可以采用二分+前序递归的方法,将中间值mid作为根节点,比mid小的放在左子树,比mid大的放在右子树。

TreeNode* dfs(vector<int>& nums , int left , int right)
    {
        if(left > right)
            return nullptr;

        int mid = (left + right) >> 1;

        TreeNode* node = new TreeNode(nums[mid]);
        node->left = dfs(nums , left , mid - 1);
        node->right = dfs(nums , mid + 1 , right);

        return node;
    }

    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return dfs(nums , 0 , nums.size() - 1);
    }

📁 98. 验证二叉搜索树

        二叉搜索树的特征就是,左子树所有节点的值都小于根节点的值,右子树所有节点的值都大于根节点的值;对二叉搜索树进行前序遍历得到的结果是一个有序数组。

        根绝二叉树性质我们可以知道,对二叉树进行前序遍历时,root节点的值一定大于上一个已经被遍历的节点值(左子树中最右节点)prev。

        递归函数返回值为是否为二叉搜索树,先遍历左子树是否二叉搜索树,在判断根节点值是否大于prev,然后在判断右子树是否是二叉搜索树。

        特殊情况:初始化prev值为最小值;如果是空间点nullptr,返回值为true。

long prev = LONG_MIN;

    bool dfs(TreeNode* root)
    {
        if(root == nullptr)
            return true;

        bool left = dfs(root->left);
        if(!left)
            return false;
        
        if(root->val <= prev)
            return false;
        prev = root->val;

        bool right = dfs(root->right);
        return right;
    }

    bool isValidBST(TreeNode* root) {
       return dfs(root);        
    }

📁 230. 二叉搜索树中第 K 小的元素

        从左往右递归,即前序遍历,依次--k,知道找到k为0的节点,这就是第k小的元素节点。

class Solution {
public:
    int count = 1;
    int ret = 0;

    int kthSmallest(TreeNode* root, int k) {
        count = k;
        dfs(root);
        return ret;    
    }

    void dfs(TreeNode* root)
    {
        if(root == nullptr)
            return ;
        
        dfs(root->left);

        count--;
        if(count == 0)
        {
            ret = root->val;
            return ;
        }

        dfs(root->right);
    }
};

📁 199. 二叉树的右视图

        l利用BFS进行层序遍历,记录下来每一层的最后一个节点元素即可。

class Solution {
public:
    vector<int> ret;

    vector<int> rightSideView(TreeNode* root) {
        if(root == nullptr)
            return vector<int>();
            
        queue<TreeNode*> q;
        q.push(root);

        while(!q.empty())
        {
            int sz = q.size();
            for(int i = 0 ; i < sz; ++i)
            {
                TreeNode* node = q.front(); q.pop();
                if(node->left)
                    q.push(node->left);
                if(node->right)
                    q.push(node->right);
                if(i == sz - 1)
                    ret.push_back(node->val);
            }

        }

        return ret;    
    }
};

📁 114. 二叉树展开为链表

        判断左子树是否为空,如果为空,当前节点root不需要展开,已经展开为链表,处理当前节点的右子树。

        如果不为空,需要找到左子树的最右节点作为右子树的根节点的前驱节点,当前节点root->left值为nullptr,右子树为左子树的根节点,处理完当前层后展开为链表,然后处理右子树。

class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode* cur = root;
        while(cur)
        {
            if(cur->left)
            {
                TreeNode* left = cur->left;
                TreeNode* prev = left;
                while(prev->right)
                    prev = prev->right;
                
                prev->right = cur->right;
                cur->right = left;
                cur->left = nullptr;
            }
            cur = cur->right;
        }
    }
};

📁 105. 从前序与中序遍历序列构造二叉树

       本题默认是所有值不重复

        前序遍历的第一个节点一定是根节点,我们在中序遍历中查找根节点,即可找到左子树和右子树。

        因此,递归遍历拿到prev中第一个节点一定是根节点,创建根节点,递归创建左子树根节点,在递归创建右子树根节点,直到数组中没有数据再能创建节点。

        我们在中序遍历中找到根节点,就能知道左子树长度和右子树长度,我们采用空间换时间的方法,记录下来中序遍历中每个节点对应的下标。

class Solution {
public:
    unordered_map<int,int> index;

    TreeNode* myBuildTree(vector<int>& preorder, vector<int>& inorder , int prev_left , int prev_right,
                        int in_left , int in_rihgt)
    {
        if(prev_left > prev_right || in_left > in_rihgt)
            return nullptr;

        //记录前序遍历中root的下标 以及中序遍历中root的下标
        int in_root = index[preorder[prev_left]];

        //新建节点
        TreeNode* root = new TreeNode(preorder[prev_left]);
        
        //记录左子树的个数
        int sz = in_root - in_left;

        root->left = myBuildTree(preorder , inorder , prev_left + 1 , prev_left + sz, 
                                in_left , in_root - 1);
        root->right = myBuildTree(preorder , inorder , prev_left + 1 + sz , prev_right, 
                                in_root + 1 , in_rihgt);

        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int sz = preorder.size();
        for(int i = 0 ; i < sz ; ++i)
            index[inorder[i]] = i;
        
        return myBuildTree(preorder , inorder , 0 , sz - 1 , 0 , sz - 1);
    }
};

📁 437. 路径总和 III

        我们采用前缀和的方法,从根节点开始,不断地往某一分支+root->val值为cur,如果满足公式:targetNum + ? = cur,如果 ? 存在,就表明上述公式成立,targetNum一定存在,ans += 齐前缀和为 ?的个数。

        步骤:判断从当前节点往上是否满足公式,如果满足,ans += 前缀和为 ?的个数;在判断左右子树,即ans += 左右子树中满足公式的前缀和的个数。

class Solution {
public:
    unordered_map<long long , long long> hash;
    
    int pathSum(TreeNode* root, int targetSum) {
        hash[0] = 1;

        return dfs(root , 0 , targetSum);
    }

    int dfs(TreeNode* root , long long cur ,long long targetSum)
    {
        if(root == nullptr)
            return 0;

        int ans = 0;
        cur += root->val;

        if(hash.find(cur - targetSum) != hash.end())
            ans += hash[cur - targetSum];

        hash[cur]++;
        ans += dfs(root->left , cur , targetSum);
        ans += dfs(root->right , cur , targetSum);
        hash[cur]--;

        return ans; 
    }
};

📁 236. 二叉树的最近公共祖先

        分为以下三种情况,递归查找p节点和q节点,如果找到向上返回,如果没有返回nullptr,分别查找左右子树。

        1. 如果左右子树递归结果为空,说明没有找到p,q节点,返回nullptr。

        2. 如果左子树为空,说明p和q节点在右子树中,p或q节点为另一个节点的最近公共祖先。

        3. 右子树为空,同理可得。

        4. 如果左右子树都不为空,说明此时,root为p和q的最近公共祖先。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == nullptr || root == p || root == q)
            return root;

        TreeNode* left = lowestCommonAncestor(root->left , p , q);
        TreeNode* right = lowestCommonAncestor(root->right , p , q);

        if(!left)
            return right;
        if(!right)
            return left;
        
        return root;
    }
};

📁 124. 二叉树中的最大路径和

        本题,我们采用后序遍历的思路,先查找左子树中最大值的路径,最查找右子树中最大值的路径,然后+上根节点的值,记录下来最大值即可。

        返回值为,从根节点开始,到左右子树中找到一条值最大的路径,向上返回该路径的值+根节点的值。

        递归结束条件就是找到叶子节点,向上返回。

class Solution {
public:
    int ret = INT_MIN;

    int maxPathSum(TreeNode* root) {
        dfs(root);
        return ret;    
    }

    int dfs(TreeNode* root)
    {
        if(root == nullptr)
            return 0;
        
        int left = max(0 , dfs(root->left));
        int right = max(0 , dfs(root->right));

        ret = max(ret , root->val + left + right);

        return root->val + max(left , right);
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2375041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用drawdb.app可视化创建mysql关系表

平时自己建表,没有可视化图形参考 为了便于理解,用drwadb画mysql关系表 drawDB | Online database diagram editor and SQL generator

火绒互联网安全软件:自主引擎,精准防御

在数字时代&#xff0c;网络安全是每一个用户都必须重视的问题。无论是个人用户还是企业用户&#xff0c;都需要一款高效、可靠的反病毒软件来保护设备免受恶意软件的侵害。今天&#xff0c;我们要介绍的 火绒互联网安全软件&#xff0c;就是这样一款由资深工程师主导研发并拥有…

【前端基础】8、CSS的选择器

一、什么是选择器&#xff1f; 根据一定的规则选出符合条件的HTML元素&#xff0c;从而为他们添加各种特定的样式。 二、选择器分类 通用选择器元素选择器类选择器id选择器属性选择器后代选择器兄弟选择器选择器组伪类 三、通用选择器&#xff08;*&#xff09; 作用&…

Gitee Team:关键领域行业DevSecOps落地的项目管理引擎

在全球数字化转型浪潮下&#xff0c;关键领域行业的软件研发正面临前所未有的挑战与机遇。国产化进程的加速推进与国防装备的智能化转型&#xff0c;对软件研发效能和质量提出了更高要求。在这样的背景下&#xff0c;Gitee Team作为国内领先的研发协作平台&#xff0c;正在为关…

网址为 http://xxx:xxxx/的网页可能暂时无法连接,或者它已永久性地移动到了新网址

这是由于浏览器默认的非安全端口所导致的&#xff0c;所谓非安全端口&#xff0c;就是浏览器出于安全问题&#xff0c;会禁止一些网络浏览向外的端口。 避免使用6000,6666这样的端口 6000-7000有很多都不行&#xff0c;所以尽量避免使用这个区间 还有在云服务器中&#xff0c…

鸿蒙跨平台开发教程之Uniapp布局基础

前两天的文章内容对uniapp开发鸿蒙应用做了一些详细的介绍&#xff0c;包括配置开发环境和项目结构目录解读&#xff0c;今天我们正式开始写代码。 入门新的开发语言往往从Hello World开始&#xff0c;Uniapp的初始化项目中已经写好了一个简单的demo&#xff0c;这里就不再赘述…

uniapp使用npm下载

uniapp的项目在使用HBuilder X创建时是不会有node_modules文件夹的&#xff0c;如下图所示&#xff1a; 但是uni-app不管基于哪个框架&#xff0c;它内部一定是有node.js的&#xff0c;否则没有办法去实现框架层面的一些东西&#xff0c;只是说它略微有点差异。具体差异表现在…

C# 的异步任务中, 如何暂停, 继续,停止任务

namespace taskTest {using System;using System.Threading;using System.Threading.Tasks;public class MyService{private Task? workTask;private readonly SemaphoreSlim semaphore new SemaphoreSlim(0, 1); // 初始为 0&#xff0c;Start() 启动时手动放行private read…

2025年AI工程师认证深度解析:AAIA认证体系全景指南与实战策略

一、IAAAI认证体系演进与价值定位 1.1 国际人工智能认证发展现状 全球人工智能认证市场呈现显著分化态势。据Gartner 2025Q1报告显示&#xff0c;北美市场以IEEE/ACM双认证体系为主导&#xff08;市占率38%&#xff09;&#xff0c;欧盟区推行AI Act合规认证&#xff08;强制…

统计服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息

文章目录 一、背景二、说明三、页面四、代码 前端 MonitorServiceProcessPage.vueMonitorServiceProcessTable.vueMonitorServiceProcessTableButton.vueaddMonitorTask.vueproductOperation.vueshowMonitorTask.vueMonitorSystemLog.vueMonitorTask.vueMonitorTaskLog.vueReal…

-MAC桢-

MAC桢和IP的关系&#xff1a; 主机A想跨网络和B通信需要IP地址进行路由选择&#xff0c;但一个局域网&#xff0c;比如路由器进行路由选择之前&#xff0c;首先要将数据包发送给路由器B&#xff0c;也就是局域网通信也就是同一个网段的主机进行通信&#xff0c;所以必须通过mac…

安装:Kali2025+Docker

安装:Kali2025Docker Kali2025安装 直接官网下载WMware版本 https://www.kali.org/get-kali/#kali-virtual-machines 直接打开运行 初始用户密码 kali/kali sudo -i 命令切换到root 更换镜像 切换到其他可用的 Kali Linux 镜像源可能会解决问题,可以使用国内的镜像源&…

Linux云计算训练营笔记day04[Rocky Linux中的命令:mv、cp、grep(^$)、tar、重定向>和>>]

mv 移动(剪切) 源数据会消失 格式: mv 源文件 目标路径 touch /opt/a.txt 创建文件 mv /opt/a.txt /root 移动文件&#xff0c;没有改名 mkdir gongli 创建目录 mv gongli /opt/ 移动目录&#xff0c;没有改名 mv /opt/gongli tedu 移动目录&#xff0c;改名了 …

AbMole Olaparib:打破常规,用PARP抑制重塑肿瘤研究

在当今的生物医学研究领域&#xff0c;Olaparib&#xff08;AZD2281&#xff0c;AbMole&#xff0c;M1664&#xff09;作为一种重要的PARP&#xff08;聚腺苷二磷酸核糖聚合酶&#xff09;抑制剂&#xff0c;受到了广泛关注。Olaparib可干扰 DNA 单链断裂的修复&#xff0c;从而…

Windows重置网络,刷新缓存

同时按键盘上的【Windows】键和【S】键&#xff0c;弹出搜索框&#xff0c;输入 命令提示符 在“最佳匹配”下的【命令提示符】上右键&#xff0c;点击【以管理员身份运行】 1弹出一个窗口&#xff0c;在光标闪烁的位置&#xff0c;直接输入【netsh winsock reset】&#xff0…

OpenHarmony平台驱动开发(十),MMC

OpenHarmony平台驱动开发&#xff08;十&#xff09; MMC 概述 功能简介 MMC&#xff08;MultiMedia Card&#xff09;即多媒体卡&#xff0c;是一种用于固态非易失性存储的小体积大容量的快闪存储卡。 MMC后续泛指一个接口协定&#xff08;一种卡式&#xff09;&#xff0…

解决IDEA无法运行git的问题

之前git一直没有问题&#xff0c;今天打开就提示我安装git&#xff0c;自然用git去提交新项目也会遇到问题。 我出现问题的原因是&#xff1a;git路径缺失 文件->设置->git 发现git的路径为空&#xff0c;按照实际位置填写即可

HTTP 响应状态码总结

一、引言 HTTP 响应状态码是超文本传输协议&#xff08;HTTP&#xff09;中服务器对客户端&#xff08;通常是 Web 浏览器&#xff09;请求的响应指示。这些状态码是三位数字代码&#xff0c;用于告知客户端请求的结果&#xff0c;包括请求是否成功。响应被分为五个类别&#…

【Qt】Qt 构建系统详解:qmake 入门到项目实战

Qt 构建系统详解&#xff1a;qmake 入门到项目实战 本文将系统介绍 Qt 构建工具 qmake 的用法&#xff0c;并通过一个完整的项目结构示例&#xff0c;帮助你掌握 .pro 文件编写、子项目管理、模块依赖等核心技能。 &#x1f9ed; 一、什么是 qmake&#xff1f; qmake 是 Qt 提…

《Zabbix Proxy分布式监控实战:从安装到配置全解析》

注意&#xff1a;实验所需的zabbix服务器的搭建可参考博客 zabbix 的docker安装_docker安装zabbix-CSDN博客 1.1 实验介绍 1.1.1 实验目的 本实验旨在搭建一个基于Zabbix的监控系统&#xff0c;通过安装和配置Zabbix Proxy、MySQL数据库以及Zabbix Agent&#xff0c;实现分…