C++力扣题目617--合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

 

思路

相信这道题目很多同学疑惑的点是如何同时遍历两个二叉树呢?

其实和遍历一个树逻辑是一样的,只不过传入两个树的节点,同时操作。

#递归

二叉树使用递归,就要想使用前中后哪种遍历方式?

本题使用哪种遍历都是可以的!

我们下面以前序遍历为例。

动画如下:

617.合并二叉树

那么我们来按照递归三部曲来解决:

  1. 确定递归函数的参数和返回值:

首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。

代码如下:

TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {

  1. 确定终止条件:

因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。

反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。

代码如下:

if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2
if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1


 

  1. 确定单层递归的逻辑:

单层递归的逻辑就比较好写了,这里我们重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。

那么单层递归中,就要把两棵树的元素加到一起。

t1->val += t2->val;

接下来t1 的左子树是:合并 t1左子树 t2左子树之后的左子树。

t1 的右子树:是 合并 t1右子树 t2右子树之后的右子树。

最终t1就是合并之后的根节点。

代码如下:

t1->left = mergeTrees(t1->left, t2->left);
t1->right = mergeTrees(t1->right, t2->right);
return t1;

此时前序遍历,完整代码就写出来了,如下:

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1// 修改了t1的数值和结构t1->val += t2->val;                             // 中t1->left = mergeTrees(t1->left, t2->left);      // 左t1->right = mergeTrees(t1->right, t2->right);   // 右return t1;}
};

那么中序遍历也是可以的,代码如下:

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1// 修改了t1的数值和结构t1->left = mergeTrees(t1->left, t2->left);      // 左t1->val += t2->val;                             // 中t1->right = mergeTrees(t1->right, t2->right);   // 右return t1;}
};

后序遍历依然可以,代码如下:

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1// 修改了t1的数值和结构t1->left = mergeTrees(t1->left, t2->left);      // 左t1->right = mergeTrees(t1->right, t2->right);   // 右t1->val += t2->val;                             // 中return t1;}
};

但是前序遍历是最好理解的,我建议大家用前序遍历来做就OK。

如上的方法修改了t1的结构,当然也可以不修改t1和t2的结构,重新定义一个树。

不修改输入树的结构,前序遍历,代码如下:

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2;if (t2 == NULL) return t1;// 重新定义新的节点,不修改原有两个树的结构TreeNode* root = new TreeNode(0);root->val = t1->val + t2->val;root->left = mergeTrees(t1->left, t2->left);root->right = mergeTrees(t1->right, t2->right);return root;}
};

#迭代法

使用迭代法,如何同时处理两棵树呢?

思路我们在二叉树:我对称么? (opens new window)中的迭代法已经讲过一次了,求二叉树对称的时候就是把两个树的节点同时加入队列进行比较。

本题我们也使用队列,模拟的层序遍历,代码如下:

class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2;if (t2 == NULL) return t1;queue<TreeNode*> que;que.push(t1);que.push(t2);while(!que.empty()) {TreeNode* node1 = que.front(); que.pop();TreeNode* node2 = que.front(); que.pop();// 此时两个节点一定不为空,val相加node1->val += node2->val;// 如果两棵树左节点都不为空,加入队列if (node1->left != NULL && node2->left != NULL) {que.push(node1->left);que.push(node2->left);}// 如果两棵树右节点都不为空,加入队列if (node1->right != NULL && node2->right != NULL) {que.push(node1->right);que.push(node2->right);}// 当t1的左节点 为空 t2左节点不为空,就赋值过去if (node1->left == NULL && node2->left != NULL) {node1->left = node2->left;}// 当t1的右节点 为空 t2右节点不为空,就赋值过去if (node1->right == NULL && node2->right != NULL) {node1->right = node2->right;}}return t1;}
};


 

#拓展

当然也可以秀一波指针的操作,这是我写的野路子,大家就随便看看就行了,以防带跑偏了。

如下代码中,想要更改二叉树的值,应该传入指向指针的指针。

代码如下:(前序遍历)

class Solution {
public:void process(TreeNode** t1, TreeNode** t2) {if ((*t1) == NULL && (*t2) == NULL) return;if ((*t1) != NULL && (*t2) != NULL) {(*t1)->val += (*t2)->val;}if ((*t1) == NULL && (*t2) != NULL) {*t1 = *t2;return;}if ((*t1) != NULL && (*t2) == NULL) {return;}process(&((*t1)->left), &((*t2)->left));process(&((*t1)->right), &((*t2)->right));}TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {process(&t1, &t2);return t1;}
};

#总结

合并二叉树,也是二叉树操作的经典题目,如果没有接触过的话,其实并不简单,因为我们习惯了操作一个二叉树,一起操作两个二叉树,还会有点懵懵的。

这不是我们第一次操作两棵二叉树了,在二叉树:我对称么? (opens new window)中也一起操作了两棵二叉树。

迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。

最后拓展中,我给了一个操作指针的野路子,大家随便看看就行了,如果学习C++的话,可以再去研究研究。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序中滚动字幕

需求&#xff1a;在录像时需要在屏幕上提示字幕&#xff0c;整体匀速向上滚动 html部分&#xff1a; <view class"subtitles_main"><view style"font-size:34rpx;color: #fff;line-height: 60rpx;" animation"{{animation}}">人生的…

腾讯云添加SSL证书

一、进入腾讯云SSL证书&#xff1a; ssl证书控制台地址 选择“我的证书”&#xff0c;点击"申请免费证书" 2、填写域名和邮箱&#xff0c;点击“提交申请” 在此页面中会出现主机记录和记录值。 2、进入云解析 DNS&#xff1a;云解析DNS地址 进入我的解析-记录…

步进电机相关知识 以及 TMC2660 步进电机驱动芯片驱动步进电机

步进电机相关知识 以及 TMC2660 步进电机驱动芯片驱动步进电机 前言一、步进电机基础知识1、电机常用概念2、步进电机小知识3、步进电机分类4、步进电机工作原理细分驱动步进电机 5、使用的步进电机型号以及相关参数 二、步进电机驱动芯片 TMC2660 和MCU端步进电机驱动芯片TMC2…

js中try...catch捕捉错误

文章目录 一、前言二、场景2.1、setTimeout2.2、Promise 三、最后 一、前言 说到try...catch都觉得非常熟悉了&#xff0c;不就是用来捕捉代码块中的错误嘛&#xff0c;平时也用得比较多的 二、场景 try...catch只能捕捉到同步执行代码块中的错误 2.1、setTimeout try {setT…

Surface mesh结构学习

CGAL 5.6 - Surface Mesh: User Manual Surface_mesh 类是半边数据结构的实现&#xff0c;可用来表示多面体表面。它是半边数据结构&#xff08;Halfedge Data Structures&#xff09;和三维多面体表面&#xff08;3D Polyhedral Surface&#xff09;这两个 CGAL 软件包的替代品…

Java Web 开发 从入门到实战(课后习题)

第1章 Web 前端基础 1.在以下标记中&#xff0c;用于改置页面标题的是&#xff08;&#xff09;。 A. <title> B. <caption> C. <head> D. <html> 注&#xff1a;caption是表格名称&#xff08;标题&#xff09; 2. 若设计网页的背景图形为bg.png&…

计算机毕业设计----SSH电子相册管理系统

项目介绍 本项目分为普通用户与管理员两个角色&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登陆,用户信息管理,登陆密码修改等功能。 用户角色包含以下功能&#xff1a; 用户登陆,个人信息管理,相册管理,上传照片等功能。 环境需要 1.运行环境&#xff1a;最好…

计算机毕业设计-----SSH计算机等级考试报名系统

项目介绍 该项目分为前后台&#xff0c;分为管理员与普通用户两种角色&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,修改个人密码&#xff0c;院系信息管理&#xff0c;注册用户管理&#xff0c;留…

Python 全栈体系【四阶】(十二)

第四章 机器学习 十五、朴素贝叶斯 朴素贝叶斯是一组功能强大且易于训练的分类器&#xff0c;它使用贝叶斯定理来确定给定一组条件的结果的概率&#xff0c;“朴素”的含义是指所给定的条件都能独立存在和发生。朴素贝叶斯是多用途分类器&#xff0c;能在很多不同的情景下找到…

“+”连接符用法(Java)

""可以作为连接符使用&#xff0c;如果与字符串一起运算&#xff0c;结果依旧是一个字符串 比如"aaa"6 --> "aaa6" 在打印中&#xff0c;能算就算&#xff0c;不能计算的时候就会连接在一起 注意先后顺序 ascii编码&#xff1a; 字符串&…

survey和surveyCV:如何用R语言进行复杂抽样设计、权重计算和10折交叉验证?

一、引言 在实际调查和研究中&#xff0c;我们往往面临着样本选择的复杂性。复杂抽样设计能够更好地反映真实情况&#xff0c;提高数据的代表性和可靠性。例如&#xff0c;多阶段抽样可以有效地解决大规模调查的问题&#xff0c;整群抽样能够在保证样本的随机性的同时减少资源消…

高颜值第三方网易云播放器R3PLAYX

什么是 R3PLAYX &#xff1f; R3PLAYX 是一款基于 YesPlayMusi-Alpha 二次开发的高颜值第三方网易云播放器。支持 Windows 、macOS 、Linux 和 Docker。目前 R3PLAYX 处于 Alpha 阶段&#xff0c;仍在开发中&#xff0c;功能尚未完善。 如果你对第三方网易云音乐播放器感兴趣&a…