Day20 222完全二叉树的节点个数 110平衡二叉树 257二叉树的所有路径

222 完全二叉树的结点个数

        本题先不把它当成完全二叉树来看,用广度优先和深度优先搜索分别遍历,也能达到目的,只要将之前的代码稍加修改即可。注意后序遍历时的result要加上自身本身的那个结点。

//后序递归遍历
class Solution {
public:int countNodes(TreeNode* root) {if(root==nullptr) return 0;int leftnum = countNodes(root->left);int rightnum = countNodes(root->right);int result = leftnum + rightnum +1;return result;}
};
//层序遍历
class Solution {
public:int countNodes(TreeNode* root) {queue<TreeNode*> que;int result = 0;if(root != NULL)que.push(root);while(!que.empty()){int size = que.size();while(size--){TreeNode* node = que.front();que.pop();result++;if(node->left)que.push(node->left);if(node->right)que.push(node->right);}}return result;}
};

        既然本题给出了条件完全二叉树,那就可以用完全二叉树的方法来做。可以继续使用递归法,终止条件要稍微变一下,要根据左右深度是否相同来判断子树是不是满二叉树,如果是的话就返回2的n次方-1,不是的话就继续递归。为什么左右深度相等就一定是满二叉树呢,这取决于完全二叉树的特性,也就是最后那层肯定是连续的,不存在中间为空的情况。

class Solution {
public:int countNodes(TreeNode* root) {if (root == nullptr) return 0;TreeNode* left = root->left;TreeNode* right = root->right;int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便while (left) {  // 求左子树深度left = left->left;leftDepth++;}while (right) { // 求右子树深度right = right->right;rightDepth++;}if (leftDepth == rightDepth) {return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0}return countNodes(root->left) + countNodes(root->right) + 1;}
};

 110 平衡二叉树

递归:

        要求高度,首先想到要后序遍历,终止条件为遍历到空节点,单层递归逻辑为:分别求出本节点左右子树的高度,如果高度等于-1,就说明左右子树之一不平衡,如果均不为-1, 就继续往下进行,比较左右子树的高度差,大于1说明有问题,返回-1,其余情况正常算高度。

class Solution {
public:int getHeight(TreeNode* node){if(node == nullptr) 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);}
};

迭代:

        本题也可以通过迭代法来进行遍历,但是不能直接用层序遍历来求高度,这就体现出求高度和求深度的不同之处。本题的迭代方式可以先定义一个函数专门求高度。

class Solution {
public:int getDepth(TreeNode*node){queue<TreeNode*> que;if(node!=nullptr) que.push(node);int depth = 0;while(!que.empty()){int size = que.size();depth++;while(size--){TreeNode* cur = que.front();que.pop();if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return depth;}bool isBalanced(TreeNode* root) {queue<TreeNode*> que;if(root == nullptr) return true;else que.push(root);while(!que.empty()){int size = que.size();while(size--){TreeNode*node=que.front();que.pop();if(abs(getDepth(node->left)-getDepth(node->right))>1)return false;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return true;}
};

257 二叉树的所有路径  

         本题很明显要进行前序遍历,才方便让父亲节点指向孩子节点,找到对应的路径。但是既然要输出所有的路径,我觉得本题是时候该考虑回溯了。

         首先是递归法:1.参数返回值:传入根节点,记录每一条路径的path,存放结果的result。

2.递归终止条件。在写递归时都习惯了写cur==null终止,但是本题如果这么写会比较麻烦,因为本题是要找到叶子节点,就结束把路径放进result里的处理了。那么为什么要用vector<int> path来记录路径呢,因为单层递归的逻辑时,要做回溯,使用vector方便回溯过程。3.确定单层递归逻辑,因为前序遍历,所以先处理中间结点,之后就是递归和回溯的过程。

        要注意:回溯要和递归永远在一起,世界上最遥远的距离是你在花括号里,而我在花括号外!有一个递归,就要对应一个回溯!

        整体代码如下:

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;}
};

         每次回溯都要pop出此时容器里存放的那个数字,这样就能找出不同的路径了。为什么要用引用呢因为既然每次都pop了,所以说这个path每次都是在变的。

可以精简成如下代码:

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;}
};

         这个代码里也有递归回溯,因为传入的这个string并不是引用形式,每次执行完毕以后,返回到上一个都不会让这次的影响对上一次进行改变,所以-》要写在递归函数里面,如果写成:

path += "->";
traversal(cur->left, path, result); // 左

         path就会被改变以后再进行递归,无法进行回溯,这回导致-》重复。如果非要这么写,就得用第一种方法把他pop出去:

if (cur->left) {path += "->";traversal(cur->left, path, result); // 左path.pop_back(); // 回溯 '>'path.pop_back(); // 回溯 '-'
}
if (cur->right) {path += "->";traversal(cur->right, path, result); // 右path.pop_back(); // 回溯 '>' path.pop_back(); //  回溯 '-' 
}

         本题也可以采用非递归的方式,类似于前序遍历的迭代法,不过要定义两个栈,一个是正常迭代法里的那个遍历栈,另一个是保存每次路径的栈:

class Solution {
public:vector<string> binaryTreePaths(TreeNode* root) {stack<TreeNode*> treeSt;// 保存树的遍历节点stack<string> pathSt;   // 保存遍历路径的节点vector<string> result;  // 保存最终路径集合if (root == NULL) return result;treeSt.push(root);pathSt.push(to_string(root->val));while (!treeSt.empty()) {TreeNode* node = treeSt.top(); treeSt.pop(); // 取出节点 中string path = pathSt.top();pathSt.pop();    // 取出该节点对应的路径if (node->left == NULL && node->right == NULL) { // 遇到叶子节点result.push_back(path);}if (node->right) { // 右treeSt.push(node->right);pathSt.push(path + "->" + to_string(node->right->val));}if (node->left) { // 左treeSt.push(node->left);pathSt.push(path + "->" + to_string(node->left->val));}}return result;}
};

         这两个栈是紧密联系的,上面动的时候,下面也会跟着动。这里的treeSt肯定是只遍历一遍的,但是pathSt里面存的是一个路径,上次遍历的部分会依旧保留,记录了之前遍历过的部分。

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

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

相关文章

STL——集合算法

算法简介&#xff1a; set_intersection // 求两个容器的交集set_union // 求两个容器的并集set_difference // 求两个容器的差集 1.set_intersection 函数原型&#xff1a; set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);…

【办公技巧】怎么批量提取文件名到excel

Excel是大家经常用来制作表格的文件&#xff0c;比如输入文件名&#xff0c;如果有大量文件需要输入&#xff0c;用张贴复制或者手动输入的方式还是很费时间的&#xff0c;今天和大家分享如何批量提取文件名。 打开需要提取文件名的文件夹&#xff0c;选中所有文件&#xff0c…

iptables 防火墙(二)

目录 1. SNAT 策略及应用 1.1 SNAT策略概述 1. 只开启路由转发&#xff0c;未设置地址转换的情况 2. 开启路由转发&#xff0c;并设置SNAT转换的情况 1.2 SNAT策略的应用 1. 2.1 共享固定IP上网 &#xff08;1&#xff09;打开网关的路由转发 &#xff08;2&#xff09;…

MongoDB 概念介绍

1、MongoDB 应用场景 传统的关系型数据库&#xff0c;在数据操作的"三高"需求以及应对Web2.0的网站需求面前&#xff0c;显得力不从心。 High performance -对数据库高并发读写的需求。Huge Storage -对海量数据的高效率存储和访问的需求。High Scalability &&…

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

C++进阶--二叉树进阶(二叉搜索树)

二叉树进阶&#xff08;二叉搜索树&#xff09; 一、二叉搜索树1.1 二叉搜索树的概念 二、二叉搜索树的结构2.1 结点结构2.2 树结构 三、二叉搜索树的操作&#xff08;非递归&#xff09;3.1 二叉搜索树的插入3.2 二叉搜索树的查找3.3 二叉搜索树的中序遍历3.4 二叉搜索树的删除…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

WPF+Halcon 培训项目实战(11):HS组件封装

文章目录 前言相关链接项目专栏运行环境匹配图片封装组件新增类库项目选择依赖顺序并添加Nuget修改原本矩形方法运行结果&#xff1a; 对矩形进行抽象封装抽象基类矩形抽象改造 圆形抽象封装代码运行结果 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率(C++)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机的固定帧率&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的固定帧率功能的技术背景CameraExplorer如何查看相机固定帧率功能在NEOAPI SDK里通过函数设置相机固定帧率 Baumer工业相机通过NEOAPI SDK设置相机固定…

harmonyOS Column组件通过space属性设置内部元素间距

例如 我们代码如下 import router from ohos.router Entry Component struct Index {build() {Row() {Column() {Text("年后")Text("一起")Text("旅游")}.width(100%)}.height(100%)} }运行之后 元素都粘连到一起 显然不太好看 我们就可以通过…

PM大逃亡

欢迎来到程序小院 PM大逃亡 玩法&#xff1a;点击白色的小鬼&#xff0c;滑动鼠标移动&#xff0c;不要碰到黑色的怪物&#xff0c; 怪物会越来越多&#xff0c;看看你能坚持多久&#xff0c;快去大逃亡吧^^。开始游戏https://www.ormcc.com/play/gameStart/233 html <div…

分享Python采集40个NET整站程序源码,总有一款适合您

分享Python采集40个NET整站程序源码&#xff0c;总有一款适合您 Python采集的40个NET整站程序源码下载链接&#xff1a;https://pan.baidu.com/s/1z54JHJkFYa4Kx2oBtPrn_w?pwd2ta4 提取码&#xff1a;2ta4 商品评论网站系统 小孔子内容管理系统XkCms V2.0 友间别墅整站程…

【win10】解决重装系统后笔记本无法调节亮度的问题

问题描述 笔记本重装系统后发现之前的fn快捷键调节亮度的功能無了&#xff0c;检查过后发现n卡控制面板&#xff0c;电源选项这些能调节屏幕亮度的地方一个都不行。笔记本一直是最强亮度非常伤眼睛。 问题分析 重装系统后发生这种情况大概率是因为之前的显卡驱动没了&#…

【rar转zip】如何将rar文件轻松转换成zip

今天和大家分享三个rar压缩包改成zip格式的方法&#xff0c;希望能够帮助到大家&#xff01; 方法一&#xff1a; 直接修改rar压缩包的后缀名变为zip&#xff0c;就可以修改压缩包文件格式了 方法二&#xff1a; 先将rar压缩包解压出来&#xff0c;然后再将解压出的文件进行…

【MATLAB】BiGRU神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 BiGRU神经网络时序预测算法是一种基于双向门控循环单元&#xff08;GRU&#xff09;的多变量时间序列预测方法。该方法结合了双向模型和门控机制&#xff0c;旨在有效地捕捉时间序列数据中…

git 常用操作合集

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

CCSK认证:开启云安全领域的黄金大门

&#x1f31f;你是否对云安全领域充满热情&#xff1f;是否希望提升自己在云安全领域的专业性和竞争力&#xff1f;CCSK认证是你的不二之选&#xff01; &#x1f525;CCSK简介&#xff1a; CCSK是国际云安全联盟&#xff08;Cloud Security Alliance&#xff0c;CSA&#xff…

【前端基础】——原型与原型链详解,看一篇即可【图文版】

前言 本文旨在通过图文的方式&#xff0c;一步步回顾原型链的整个流程是如何运作的&#xff0c;如果你刚好在电脑旁边&#xff0c;不妨跟着我的思路&#xff0c;一起走一遍敲一遍代码流程&#xff0c;你会发现原型链并没有你想的那么复杂。 new关键字 我们先看这一个代码&am…

RIS 系列 See-Through-Text Grouping for Referring Image Segmentation 论文阅读笔记

RIS 系列 See-Through-Text Grouping for Referring Image Segmentation 论文阅读笔记 一、Abstract二、引言三、相关工作3.1 Semantic Segmentation and Embeddings3.2 Referring Expression Comprehension3.3 Referring Image Segmentation 四、方法4.1 视觉表示4.2 文本表示…

【yolofastest上手】

一、前言 yolofastest网上资料比较少&#xff0c;也没有视频教学&#xff0c;所以想要使用参考了很多资料&#xff0c;只能说各资料都不尽全&#xff0c;让刚接触的小白无从下手。 参考资料: github地址 yolo-fastest 快速上手 修改参数遇到的问题 能在ARM-CPU上实时识别图像的…