代码随想录算法训练营DAY17|C++二叉树Part.4|110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

文章目录

  • 110.平衡二叉树
    • 思路
    • 伪代码
    • CPP代码
  • 257.二叉树的所有路径
    • 思路
    • 伪代码实现
    • CPP代码
  • 404.左叶子之和
    • 思路
    • 伪代码
    • CPP代码

110.平衡二叉树

力扣题目链接

文章讲解:110.平衡二叉树

视频讲解:后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树

状态:第一眼要用后序遍历,因为对于某结点我们需要收集其左右孩子的信息。

思路

本题中,平衡二叉树的定义就是:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1

并且既然是要求比较高度,必然要使用后序遍历。

这里的递归函数,通过返回二叉树的高度是最好的,即使我们不需要求二叉树的高度。因为在计算高度的过程中,我们才好去判断左右子树的高度差。

所以一定要注意的就是我们的递归函数代码本质上是求二叉树的高度,而不是直接去判断是否是平衡二叉树。


还有一个一定要注意的情况:
在这里插入图片描述
该二叉树不是平衡二叉树!因为左结点的2,其左孩子高度为2,右孩子高度为0!所以不是平衡二叉树,在代码中一定要考虑这种情况!

伪代码

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

    参数:当前结点;返回值:应当是以当前结点为根结点的树的高度。

// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
int getHeight(TreeNode* node)
  • 明确终止条件:递归的过程中依然是遇到空结点了为终止,返回0,表示当前结点为根结点的树的高度为0
if (node == NULL)return 0
  • 确定单层递归逻辑:

如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值

分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。

int leftHeight = getHeight(node->left); //左
if (leftHeight == -1) return -1;		//思考思考这行代码的作用
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;		//同上int result;
if (abs(leftHeight - rightHeight) <= 1)result = 1 + max(leftHeight, rightHeight);
elsereturn -1;return result;

代码if (leftHeight == -1) return -1这行代码一定要写上,因为他们也同样是在求高度,如果该根结点左子树的高度已经返回了-1,那么这颗树肯定不是平衡二叉树!

  • 单层递归逻辑精简后的代码:
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);

CPP代码

class Solution {
public:// 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1int getHeight(TreeNode* node) {if (node == NULL) {return 0;}int leftHeight = getHeight(node->left);if (leftHeight == -1) return -1;int rightHeight = getHeight(node->right);if (rightHeight == -1) return -1;return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);}bool isBalanced(TreeNode* root) {return getHeight(root) == -1 ? false : true;}
};

257.二叉树的所有路径

力扣题目链接

文章讲解:257.二叉树的所有路径

视频讲解:递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径

状态:只知道用前序遍历,剩下的代码特别是关于单层递归逻辑那里根本就写不出来,如何处理遇到分叉路口的情况呢?(即回溯逻辑) 还有一个要注意的点就是关于递归终止条件,本题的终止条件和之前的有什么不一样呢?

思路

本题其实就是求二叉树的遍历路径,那么我们就一定要保存从根结点开始遍历的路径。

很明显,要使用前序遍历。并且在本题中要有回溯的逻辑。

20210204151702443

伪代码实现

  • 确定递归函数的参数和返回值:我们传入的参数就包含了要记录结果的数组,所以返回值肯定是void,至于参数包括传入根节点,记录每一条路径的path,和存放结果集的result
void traversal(TreeNode* node, vector<string>& result, vector<int>& path){
} 
  • 确定递归终止条件:之前的题目都是遍历到空结点即可终止递归;但是在本题中,我们是要寻找到叶子结点(防止左叶子为空,右叶子不为空的情况)才能终止。因为我们本质上要确定是叶子结点的时候,才能真正的结束。而且由于我们对最后遍历的叶子结点要进行操作,所以返回的地方一定要是该叶子结点,而不能是 node == NULL 的时候。
if (node == NULL) return;//No!
if (node->left == NULL && node->right == NULL) {处理逻辑
}

为什么没有判断cur是否为空呢,因为下面的逻辑可以控制空节点不入循环。

再来看一下终止处理的逻辑:这里使用vector 结构path来记录路径,所以要把vector 结构的path转为string格式,再把这个string 放进 result里。

那么为什么使用了vector 结构来记录路径呢?

因为在下面处理单层递归逻辑的时候,要做回溯,使用vector方便来做回溯。

if (node->left == NULL && node->right == NULL) {	//遇到了叶子结点string sPath;for (int i = 0; i < path.size() - 1; i++){	//将path里记录的路径转换为string格式sPath += to_string(path[i]);sPath += "->";}sPath += to_string(path[path.size() - 1]);	//记录当前叶子结点result.push_back(sPath);	//收集一个路径return;
} 
  • 确定单层递归逻辑:上面说过没有判断cur是否为空,那么在这里递归的时候,如果为空就不进行下一层递归了

    • 上面的代码写到遍历到叶子结点我们就终止循环,那么什么时候把叶子结点压入path中呢?写到终止条件的前一步即可
    • 单层递归逻辑里面最难的其实就是如何进行回溯?其实就是对**path中的结点进行删除,然后加入新结点**。所以在代码中回溯和递归一定要一一对应,有一个递归就要有一个回溯。所以下面的代码逻辑是错的:
    if (cur->left) {traversal(cur->left, path, result);
    }
    if (cur->right) {traversal(cur->right, path, result);
    }
    path.pop_back();
    //这么写相当于把递归和回溯拆开了,一个在花括号里,一个在花括号外。//正确写法
    path.push_back(cur->val);	//中if (cur->left) {					//左traversal(cur->left, path, result);path.pop_back(); // 回溯
    }
    if (cur->right) {					//右traversal(cur->right, path, result);path.pop_back(); // 回溯
    }
    

CPP代码

class Solution {
private:void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {path.push_back(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中 // 这才到了叶子节点if (cur->left == NULL && cur->right == NULL) {string sPath;for (int i = 0; i < path.size() - 1; i++) {sPath += to_string(path[i]);sPath += "->";}sPath += to_string(path[path.size() - 1]);result.push_back(sPath);return;}if (cur->left) { // 左 traversal(cur->left, path, result);path.pop_back(); // 回溯}if (cur->right) { // 右traversal(cur->right, path, result);path.pop_back(); // 回溯}}public:vector<string> binaryTreePaths(TreeNode* root) {vector<string> result;vector<int> path;if (root == NULL) return result;traversal(root, path, result);return result;}
};

精简版代码:


//精简版代码隐藏了回溯过程
class Solution {
private:void traversal(TreeNode* cur, string path, vector<string>& result) {path += to_string(cur->val); // 中if (cur->left == NULL && cur->right == NULL) {result.push_back(path);return;}if (cur->left) traversal(cur->left, path + "->", result); // 左if (cur->right) traversal(cur->right, path + "->", result); // 右}public:vector<string> binaryTreePaths(TreeNode* root) {vector<string> result;string path;if (root == NULL) return result;traversal(root, path, result);return result;}
};

注意在函数定义的时候void traversal(TreeNode* cur, string path, vector<string>& result) ,定义的是string path,每次都是复制赋值,不用使用引用,否则就无法做到回溯的效果。(这里涉及到C++语法知识)

那么在如上代码中,貌似没有看到回溯的逻辑,其实不然,回溯就隐藏在traversal(cur->left, path + "->", result);中的 path + "->" 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。

404.左叶子之和

力扣题目链接

文章讲解:404.左叶子之和

视频讲解:二叉树的题目中,总有一些规则让你找不到北 | LeetCode:404.左叶子之和

状态:还是有思路,我们的cur遍历到叶子结点的前一个结点,也就是cur结点的左结点的(左结点和右结点)为空,这样我们就能顺利找到左叶子。

思路

思路主要就是状态栏中的思路,主要是注意代码细节,代码实现个人感觉还是比较有难度的。

伪代码

  • 确定递归的返回值和参数:判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int

    使用题目中给出的函数就可以了。

    int getSum(TreeNode* root){
    }
    
  • 确定递归的终止条件:遍历到空结点,左叶子值为0;当前遍历到叶子结点,左叶子值仍然为0

if (root == NULL) return 0;
if (root->left == NULL && root->right == NULL) 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;

CPP代码

class Solution {
public:int sumOfLeftLeaves(TreeNode* root) {if (root == NULL) return 0;if (root->left == NULL && root->right== NULL) 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) {if (root == NULL) return 0;int leftValue = 0;if (root->left != NULL && root->left->left == NULL && root->left->right == NULL) {leftValue = root->left->val;}return leftValue + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);}
};

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

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

相关文章

lua学习笔记6(经典问题输出99乘法表)

print("************for循环的99乘法表*************") for i 1, 9 dolocal line "" -- 创建一个局部变量来累积每行的输出--local 是一个关键字&#xff0c;用于声明一个局部变量。for j 1, i doline line .. j .. "*" .. i .. ""…

电脑桌面上表格不见了怎么找回?这5个方法不要错过

在日常的办公和学习中&#xff0c;电脑桌面上的各种文件、文件夹和表格等无疑是我们较为频繁使用的资源。然而&#xff0c;有时我们可能会因为一些操作失误或者电脑问题&#xff0c;突然发现桌面上的某个表格文件神秘失踪了。面对这种情况&#xff0c;很多人可能会感到焦虑和不…

[WIP]Sora相关工作汇总VQGAN、MAGVIT、VideoPoet

视觉任务相对语言任务种类较多(detection, grounding, etc.)、粒度不同 (object-level, patch-level, pixel-level, etc.)&#xff0c;且部分任务差异较大&#xff0c;利用Tokenizer核心则为如何把其他模态映射到language space&#xff0c;并能让语言模型更好理解不同的视觉任…

Python-VBA函数基础知识-001

一、函数的定义&#xff1a; 函数(Function)是一段可重复使用的代码块&#xff0c;用于执行特定的任务或计算&#xff0c;并可以接受输入参数和返回输出结果。函数可以将复杂的问题分解为更小的子问题&#xff0c;提高代码的可读性和可维护性。 二、函数的组成&#xff1a; 在…

Spring Boot集成JWT快速入门demo

1.JWT是什么&#xff1f; JWT&#xff0c;英文全称JSON Web Token&#xff1a;JSON网络令牌。为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准(RFC 7519)。这个规范允许我们使用JWT在客户端和服务端之间传递安全可靠的信息。JWT是一个轻便的安全跨平台传输格式&am…

前端零基础学习web3开发

目录 1 钱包 2 发起交易 3 出块 4 块高 5 矿工 6 Gas费 这一节&#xff0c;我们不说让人神往的比特币&#xff0c;不说自己会不会利用这个虚拟的货币来发财&#xff0c;也不说那些模模糊糊的知识&#xff0c;什么去中心化啦&#xff0c;什么奇妙的加密啦&#xff0c;我们…

AI 驱动强大是视频转换处理软件

由 AI 驱动的视频工具包。 增强、转换、录制和编辑视频AI 驱动的顶级视频工具包。 不论是老旧、低质、噪声或模糊的影片/图像&#xff0c;都能升级至 4K&#xff0c;稳定抖动的影片&#xff0c;提升帧率至 120/240fps&#xff0c;并能以全面 GPU 加速进行转换、压缩、录制和编辑…

盘点那些好用的SAP FIORI App (四)-应收账期报告

这个App的ID是IDCNAR, 其实也是一个T-Code, 也就是说&#xff0c;不光在FIORI app里面可以使用&#xff0c;在SAP GUI里面也是存在的&#xff0c;这个就属于我另一篇里面提到的&#xff0c;GUI和FIORI都可以使用的功能&#xff0c;但是前提是S4 HANA平台 操作的界面非常简单&am…

linux进阶篇:磁盘管理(一):LVM逻辑卷基本概念及LVM的工作原理

Linux磁盘管理(一)&#xff1a;LVM逻辑卷基本概念及LVM的工作原理 一、传统的磁盘管理 在传统的磁盘管理方案中&#xff0c;如果我们的磁盘容量不够了&#xff0c;那这个时候应该要加一块硬盘&#xff0c;但是新增加的硬盘是作为独立的文件系统存在的&#xff0c;原有的文件系…

即插即用篇 | RTDETR引入Haar小波下采样 | 一种简单而有效的语义分割下采样模块

本改进已集成到 RT-DETR-Magic 框架。 下采样操作如最大池化或步幅卷积在卷积神经网络(CNNs)中被广泛应用,用于聚合局部特征、扩大感受野并减少计算负担。然而,对于语义分割任务,对局部邻域的特征进行池化可能导致重要的空间信息丢失,这有助于逐像素预测。为了解决这个问…

接口日志处理类

类&#xff1a;ZCL_IFLOG_UTILITIES 属性&#xff1a;AUTH_RESULTS_LIST 类型&#xff1a; TY_AUTH_RESULT Private 受保护部分&#xff1a; PRIVATE SECTION.TYPES: BEGIN OF ty_auth_result,funcname TYPE ztall_logcfg-funcname,pass TYPE abap_bool,END OF ty_aut…

商城系统如何设计表

小商城&#xff1a;参考千小夜小程序 大商城&#xff1a; 首先根据某个商品的三级分类进来后&#xff0c;我们找到在这个分类下该商品的所有属性&#xff08;也就是泛指该商品不管怎么样都有这些属性&#xff09;&#xff0c;这里指的属性是规格包装&#xff0c;也就是基本属性…

线程池CompletableFuture异步编排复习笔记

一、线程回顾 1.1 初始化线程的 4 种方式 1&#xff09;、继承 Thread public static class Thread01 extends Thread {Overridepublic void run() {System.out.println("当前线程&#xff1a;" Thread.currentThread().getId());int i 10 / 2;System.out.print…

机器学习周记(第三十三周:文献阅读[GWO-GART])2024.4.1~2024.4.7

目录 摘要 ABSTRACT 1 论文信息 1.1 论文标题 1.2 论文摘要 1.3 论文数据集 1.4 论文模型 2 相关知识 摘要 本周阅读了一篇使用GAT结合GRU预测PM2.5浓度的文章。论文模型为图注意力循环网络&#xff08;GART&#xff09;&#xff0c;首次提出了一种新型的多层GAT架构&…

AI预测福彩3D第27弹【2024年4月5日预测--第4套算法重新开始计算第12次测试】

今天继续按照合并后的算法进行测试&#xff0c;因为本套算法的命中率较高。以后有时间的话会在第二篇文章中发布排列3的预测结果。好了&#xff0c;废话不多说了&#xff0c;先上预测结果图&#xff0c;再上综合预测结果~ 2024年4月5日福彩3D的七码预测结果如下 第一套…

关于代码审查的一些思考

作为一名代码审查员&#xff0c;首先我们已经具备了丰富的代码开发经验&#xff0c;并且对提交的代码工程非常熟悉 代码审查可以发现并纠正代码中的错误、缺陷和不良实践。通过多人对代码进行仔细的检查和讨论&#xff0c;能够发现一些单独开发时难以察觉的问题&#xff0c;从…

5G智慧水利数字孪生可视化平台,推进水利行业数字化转型

5G智慧水利数字孪生可视化平台&#xff0c;推进水利行业数字化转型。随着5G技术的快速发展&#xff0c;越来越多的行业开始探索数字化转型的道路。水利行业作为国民经济的重要支柱&#xff0c;也面临着数字化转型的迫切需求。5G智慧水利数字孪生可视化平台作为水利行业数字化转…

Integer的缓存机制

LeetCode练习题--567.字符串的排列 今天刷题的时候,突然发现了一个问题: 为什么明明是相同的Integer值,有的时候使用""就可以,有的时候则必须使用equals方法来进行判断??? 于是我开始在网上查阅资料,几经无果,我开始阅读源码,一段时间后我才知道:原来Integer还有…

global关键字

global关键字 如果你想在局部作用域中修改全局变量&#xff0c;可以基于global关键字进行实现 默认情况下&#xff0c;在局部变量作用域只能对全局变量进行&#xff1a; 读取和修改内部元素&#xff08;可变类型&#xff09;&#xff0c;无法对全局变量进行重新赋值 读取 …

ZS卧式不锈钢离心泵

一、结构与设计特点ZS卧式不锈钢离心泵是一种高效能、耐腐蚀的泵类设备&#xff0c;其核心结构包括电机、泵体、叶轮、轴封和底座等部分。泵体采用优质不锈钢材料&#xff0c;确保了良好的耐蚀性和强度&#xff0c;同时&#xff0c;流道设计优化&#xff0c;减少了流动损失&…