【OJ】C++ | 二叉树进阶 · 合集(2)

摘要:根据二叉树创建字符串、二叉树的最近公共祖先、二叉树的层序遍历

前言:承接上文,本文继续提供二叉树进阶有关题目的解法。如有错误,烦请指正。


目录

1. 根据二叉树创建字符串

题解及代码

2. 二叉树的最近公共祖先

题解及代码

3. 二叉树的层序遍历

题解

代码


1. 根据二叉树创建字符串

题源:606. 根据二叉树创建字符串 - 力扣(LeetCode)

给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。

空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

示例 1:

输入:root = [1,2,3,4]
输出:"1(2(4))(3)"
解释:初步转化后得到 "1(2(4)())(3()())" ,但省略所有不必要的空括号对后,字符串应该是"1(2(4))(3)" 。

示例 2:

输入:root = [1,2,3,null,4]
输出:"1(2()(4))(3)"
解释:和第一个示例类似,但是无法省略第一个空括号对,否则会破坏输入与输出一一映射的关系。

提示:

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

题解及代码

  • 方式一:递归 + 处理括号。对于每个递归的子问题:括号有4种情况,①root()(sub_right);②root(sub_left)(sub_right);③root(sub_left);④root;以上这4种情况可归纳为:(一)sub_right 存在(①②);(二)sub_right 不存在(③④).
    class Solution {
    public:
        void _tree2str(TreeNode* rootP,string& ret)
        {
            if(rootP == nullptr)
                return;
    
            ret += to_string(rootP->val);
            if(rootP->right != nullptr)
            {
                if(rootP->left == nullptr)//①
                {
                    ret += "()";
                    ret += '(';
                    _tree2str(rootP->right,ret);
                    ret += ')';
                }   
                else//②
                {
                    ret += '(';
                    _tree2str(rootP->left,ret);
                    ret += ')';
                    ret += '(';
                    _tree2str(rootP->right,ret);
                    ret += ')';
                }
            }
            else
            {
                if(rootP->left == nullptr)//③
                {
                    _tree2str(rootP->right,ret);
                    _tree2str(rootP->left,ret);
                }
                else//④
                {
                    ret += '(';
                    _tree2str(rootP->left,ret);
                    ret += ')';
                }      
            }
        }
        string tree2str(TreeNode* root) 
        {
            if (root == nullptr)
                return "";
    
            string ret;
            _tree2str(root,ret);
            return ret;
        }
    };
  • 方式二:模拟递归(“非递归”) + 处理括号(此处建议看过 上一篇二叉树进阶题合集最后三题 对于非递归的思路的讲解之后再看) 

紧承上篇的结尾的总结,则我们可容易得出如下图解:

①进入root层:递归进入 root 层,并判断作左子树是否为空,为空则继续判断右子树;
②返回root层:左子树为空/递归完,判断右子树是否为空,不为空就接着递归右子树;
③第二次返回root层:右子树为空/递归完,判断右子树是否访问完毕,访问完则结束。
关键:区分是第几次返回root层。→ 可以通过一个变量来记录。

class Solution {
public:
    string tree2str(TreeNode* root) 
    {
        if (root == nullptr)
            return "";

        string ret;
        stack<pair<TreeNode*,bool>> st;
        TreeNode* CurP = root;

        while (CurP || !st.empty()) 
        {
            while (CurP) 
            {
                st.push(make_pair(CurP,1));
                ret += to_string(CurP->val);
                //cout << "ret += to_string(CurP->val);";


                if(CurP->left || CurP->right)
                    ret += '(';
                CurP = CurP->left;
            }
            pair<TreeNode*,bool>& topPr = st.top();
            TreeNode* tp = topPr.first;
            
            if (tp->right == nullptr)
            {
                if(tp->left != nullptr)
                    ret += ")";
                
                //左右子树的结点没有任何括号
                st.pop();//该层递归结束
            } 
            else // topP右不空
            {
                if(topPr.second == 1) //右子树存在且未被访问
                {
                      
                    ret += ")(";
                    topPr.second = false;
                    CurP = tp->right;
                }
                else //右子树存在但被访问完了
                {
                    ret += ')';
                    st.pop();//该层递归结束
                }
            }
        }
        //_tree2str(root,ret);
        return ret;
    }
};

2. 二叉树的最近公共祖先

题源:236. 二叉树的最近公共祖先 - 力扣(LeetCode)

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

题解及代码

方式一:根据最近公共节点的特点来解题。
根据题目描述可知:p,q两节点一定分别位于最近公共祖先节点的左子树或右子树(或者其中一个节点本身就是最近公共节点)

class Solution {
public:
    bool Findsubtree(TreeNode* root,TreeNode* node)
    {
        if(root == node)
            return true;
        
        if(root == nullptr)
            return false;

        return Findsubtree(root->right,node) || Findsubtree(root->left,node);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        if(root == nullptr)
            return nullptr;
        if(root == p || root == q)
            return root;

        bool pInLeft = Findsubtree(root->left,p);//p位于root的左子树
        bool pInRight = !pInLeft;//p位于root的右子树(同:不位于root的左子树)

        bool qInLeft = Findsubtree(root->left,q);//同上
        bool qInRight = !qInLeft;//同上

        if((pInLeft && qInRight) || (pInRight && qInLeft))//若p,q分别位于左右子树,则该层root为最近公共祖先节点
            return root;
        
        if(pInLeft && qInLeft)//如果都位于左子树则得递归到左子树去找最近公共祖先节点
            return lowestCommonAncestor(root->left,p,q);
        
        if(pInRight && qInRight)//如果都位于右子树则得递归到右子树去找最近公共祖先节点
            return lowestCommonAncestor(root->right,p,q);

        return nullptr;//按代码运行逻辑不会走到这句,但是这里对返回值的编译检查比较严格。
    }
};

方式二:找到从根节点分别“走”到p,q节点的路径。在这两个路径中,从p,q节点开始往前看,第一个相等的结点就是最近公共祖先。即:
pathOfp{x,x,x,x,x,a,b,……,p}
pathOfq{x,x,x,x,x,y,z,w,……,q}
关键在于:如何找到这两条路径?
​​答:找到路径中所含的每个节点的特征——该节点的子树中一定含有p或q节点(或者该节点本身就是p或q节点)。→ 找路径的思路:依次递归每个节点,递归到该节点的时候,该节点push入栈,再去递归该节点的左子树和右子树,如果该节点的左子树和右子树中有没有要找的结点,那么该节点不属于路径中的结点,则pop该节点。接着去递归别的节点。

如该图所示,目标是从根节点找到节点4。首先,节点3递归左子树到节点5,节点5递归左子树到节点6,节点6的左子树为空未找到节点4,节点6的左子树返回false,节点6的左子树同理返回false,由于节点6的左右子树都为false,即都未找到节点4则节点6不是该路径中的结点,节点6将被pop出栈,并且,节点6作为节点5的左子树,递归的结果点为false。然后继续递归节点5的右子树。

class Solution {
public:
    bool FindPath(TreeNode* root,TreeNode* node,stack<TreeNode*>& path)
    {   
        if(root == nullptr)
        {
            return false;
        }

        path.push(root);
        if(root == node)
            return true;
        
        if(FindPath(root->left,node,path))
            return true;
        if(FindPath(root->right,node,path))
            return true;

        path.pop();
        return false;
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        if(root == nullptr)
            return nullptr;
        if(root == p || root == q)
            return root;
        
        stack<TreeNode*> pathOfp,pathOfq;
        FindPath(root,p,pathOfp);
        FindPath(root,q,pathOfq);

        while(pathOfp.top() != pathOfq.top())
        {
            if(pathOfp.size() < pathOfq.size())
            {
                pathOfq.pop();
            }
            else
            {
                pathOfp.pop();
            }
        }
        return pathOfp.top();
    }
};

3. 二叉树的层序遍历

题源:102. 二叉树的层序遍历 - 力扣(LeetCode)107. 二叉树的层序遍历 II - 力扣(LeetCode)

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

题解

C++初阶 | [十] stack 和 queue在该篇文章中的【queue OJ】部分的内容给本题的出了思路。

下面给的代码为思路三的解法。

代码

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

        vector<vector<int>> ret;
        size_t levelSize = 0;
        queue<TreeNode*> qTree;
        TreeNode* CurP = root;
        qTree.push(CurP);
        levelSize = qTree.size();
        while(!qTree.empty())
        {
            vector<int> tmp = {};
            while(levelSize--)
            {
                CurP = qTree.front();
                if(CurP->left)
                {
                    qTree.push(CurP->left);
                }
                if(CurP->right)
                {
                    qTree.push(CurP->right);
                }
                tmp.push_back(CurP->val);
                qTree.pop();
            }
            ret.push_back(tmp);
            levelSize = qTree.size();
        }

        return ret;
    }
};

END

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PHAR反序列化

PHAR PHAR&#xff08;PHP Archive&#xff09;文件是一种归档文件格式&#xff0c;phar文件本质上是一种压缩文件&#xff0c;会以序列化的形式存储用户自定义的meta-data。当受影响的文件操作函数调用phar文件时&#xff0c;会自动反序列化meta-data内的内容,这里就是我们反序…

2024年06月编程语言流行度排名

点击查看最新编程语言流行度排名&#xff08;每月更新&#xff09; 2024年06月编程语言流行度排名 编程语言流行度排名是通过分析在谷歌上搜索语言教程的频率而创建的 一门语言教程被搜索的次数越多&#xff0c;大家就会认为该语言越受欢迎。这是一个领先指标。原始数据来自…

JAVA和爬虫,那个值得学习

如果你是初学者&#xff0c;建议先从基础的编程语言学起&#xff0c;比如Java&#xff0c;它能为你打下坚实的编程基础&#xff0c;并且在未来转学其他语言或技术时更加容易。随着编程基础的建立&#xff0c;你可以根据自己的兴趣或职业规划&#xff0c;学习爬虫技术作为补充技…

使用python下载股票数据至sqlite数据库

代码下载地址&#xff1a; https://download.csdn.net/download/weixin_44600457/89389489

961题库 北航计算机 计算机网络 附答案 选择题形式

有题目和答案&#xff0c;没有解析&#xff0c;不懂的题问大模型即可&#xff0c;无偿分享。 第1组 习题 OSI 参考模型的第 5 层( 自下而上 ) 完成的主要功能是 A. 差错控制 B. 路由选择 C. 会话管理 D. 数据表示转换 100BaseT 快速以太网使用的导向传输介质是 A. 双绞线 B. …

德人合科技——@天锐绿盾 | -文档透明加密系统

天锐绿盾文档透明加密系统是一种先进的数据安全解决方案&#xff0c;旨在保护企业和组织的敏感信息&#xff0c;防止未经授权的访问和泄漏。 PC地址&#xff1a; https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 以下是该系统的一些关键特点和功…

FJSP:常春藤算法(Ivy algorithm,LVYA)求解柔性作业车间调度问题(FJSP),提供MATLAB代码

详细介绍 FJSP&#xff1a;常春藤算法&#xff08;Ivy algorithm&#xff0c;LVYA&#xff09;求解柔性作业车间调度问题&#xff08;FJSP&#xff09;&#xff0c;提供MATLAB代码-CSDN博客 完整MATLAB代码 FJSP&#xff1a;常春藤算法&#xff08;Ivy algorithm&#xff0c;…

随后记: uniapp uview u-dropdown 下拉菜单固定高度滑动不生效

使用u-dropdown 下拉组件 按照uview官网讲解使用 配置根本不生效 scroll-y"true" style"height: 200rpx;" 但是在下拉的时候&#xff0c;不能上下滑动 &#xff0c;原因是自带的遮罩层挡住了 解决办法&#xff1a;在下拉菜单打开和关闭的时候&#xff0c…

英语四级翻译练习笔记②——大学英语四级考试2023年12月真题(第二套)

目录 引言&#xff08;必看&#xff09; 四级翻译评分标准分析及真题解析 四级翻译评分标准 四级翻译真题 学生作答 错误标注 标准满分答案 提高翻译水平的建议 引言&#xff08;必看&#xff09; 这是一篇英语四级翻译的练习的专栏&#xff0c;如果相信我的话就将这…

树莓派5烧系统和ssh远程实现

1、硬件说明 树莓派5 64G micro SD卡读卡器 2、烧录系统过程记录 之前写过一篇pi4B烧录Ubuntu22.04的博客&#xff0c;这篇就简单记录备份下 2.1 去ubuntu官网在树莓派上安装Ubuntu | Ubuntu下载Ubuntu 桌面 24.04 LTS 我之前已经下好了就有个(1) 2.2 用读卡器把SD卡插到…

车辆前向碰撞预警系统性能要求和测试规程

前言 本文整理《GB/T 33577-2017 智能运输系统-车辆前向碰撞预警系统性能要求和测试规程》国标文件关键信息,FCW系统性能和测试右给深层次的认识。 术语和定义 车辆前向碰撞预警系统 forward vehicle collision warning system自车 subject vehicle(SV)目标车辆 target ve…

Lagrange ZK Coprocessor:革新区块链领域的大数据应用

1. 引言 2024年5月11日&#xff0c;Lagrange Labs宣称获得由Founders Fund领投&#xff08;Archetype Ventures, 1kx, Maven11, Fenbushi Capital, Volt Capital, CMT Digital, Mantle Ecosystem Fund和其它天使投资人跟头&#xff09;的1320万美金种子轮融资&#xff0c;致力于…

【spring】第一篇 IOC和DI入门案例

Spring到底是如何来实现IOC和DI的&#xff0c;那接下来就通过一些简单的入门案例&#xff0c;来演示下具体实现过程。 目录 前期准备 一、IOC入门案例 思路分析 代码实现 二、DI入门案例 思路分析 代码实现 总结 前期准备 使用IDEA创建Maven项目&#xff0c;首先需要配…

linux进阶的一些操作以及知识点------习题集(实践)

请创建以你姓名全拼的用户luwenhua&#xff0c;将其设置为免密登录&#xff0c;切换到luwenhua用户&#xff0c;打开终端&#xff0c;完成以下操作 &#xff08;一&#xff09;bash脚本基础练习 1&#xff09;第一题&#xff1a;请在终端里定义两个用户变量num120&#xff0c…

来自大厂硬盘的降维打击!当希捷酷玩520 1TB SSD卷到369,请问阁下该怎么应对?

来自大厂硬盘的降维打击&#xff01;当希捷酷玩520 1TB SSD卷到369&#xff0c;请问阁下该怎么应对&#xff1f; 哈喽小伙伴们好&#xff0c;我是Stark-C~ 今年4月份的时候因为电脑上的游戏盘突然挂掉&#xff0c;为了性价比选购了希捷酷玩520 1TB SSD&#xff0c;同时我也是…

中国历年肥料进口数量统计报告

数据来源于国家统计局&#xff0c;为1991年到2021年我国每年肥料进口数量统计。 2021年&#xff0c;我国进口肥料909万吨&#xff0c;比上年减少151万吨。 数据统计单位为&#xff1a;万吨 数据说明&#xff1a; 数据来源于国家统计局&#xff0c;为海关进出口统计数 我国肥料…

网络网络层

data: 2024/5/25 14:02:20 周六 limou3434 叠甲&#xff1a;以下文章主要是依靠我的实际编码学习中总结出来的经验之谈&#xff0c;求逻辑自洽&#xff0c;不能百分百保证正确&#xff0c;有错误、未定义、不合适的内容请尽情指出&#xff01; 文章目录 1.协议结构2.封装分离3.…

SpringBoot与MyBatis零XML配置集成(附源码)

源代码先行&#xff1a; Gitee本文介绍的完整仓库&#xff1a;https://gitee.com/obullxl/ntopic-bootGitHub本文介绍的完整仓库&#xff1a;https://github.com/obullxl/ntopic-boot 背景介绍 在Java众多的ORM框架里面&#xff0c;MyBatis是比较轻量级框架之一&#xff0c;…

【JavaEE进阶】——MyBatis操作数据库 (#{}与${} 以及 动态SQL)

目录 &#x1f6a9;#{}和${} &#x1f388;#{} 和 ${}区别 &#x1f388;${}使用场景 &#x1f4dd;排序功能 &#x1f4dd;like 查询 &#x1f6a9;数据库连接池 &#x1f388;数据库连接池使⽤ &#x1f6a9;MySQL开发企业规范 &#x1f6a9;动态sql &#x1f388…

PCIe总线-事物层之TLP路由介绍(七)

1.概述 下图是一个PCIe总线系统示意图。此时RC发出一个TLP&#xff0c;经过Switch访问EP&#xff0c;TLP的路径为红色箭头所示。首先TLP从RC的下行OUT端口发出&#xff0c;Switch的上行IN端口接收到该TLP后&#xff0c;根据其路由信息&#xff0c;将其转发到Switch的下行OUT端…