代码随想录第十五天 二叉树层序遍历 226、101
二叉树的层序遍历
层序遍历相比较迭代和递归来说,简单很多。使用额外容器queue
来存放结点,将一层的元素存入到队列中,再按顺序输出。因为队列是先进先出,所以按照左右的顺序正常压入就行。代码如下:
vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;vector<vector<int>> ans;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size(); //que的size表示这次需要处理几个结点vector<int> vec;while(size--){TreeNode* cur = que.front(); //当前需要处理的结点que.pop();vec.push_back(cur->val);//弹出后需要将其左右孩子压入队列,在下一次循环中遍历if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}ans.push_back(vec);vec.clear();}return ans;}
因为这里输出的是二维数组,所以在while循环中需要初始化一个储存当前层的元素。
LeetCode 637. 二叉树的层平均值
vector<double> averageOfLevels(TreeNode* root) {vector<double> ans;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();double sum = 0;for(int i = 0; i < size ; i++){TreeNode* cur = que.front();sum += cur->val;que.pop();if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}ans.push_back(sum / size);}return ans;}
本题需要注意的就是sum
需要是double
类型。另外因为需要求平均值,所以不能使用while(size--)
循环,改为for(int i = 0; i < size ; i++)
。
LeetCode 429. N 叉树的层序遍历
这题其实没什么东西,很简单。只不过是在处理当前节点的子节点时,从左右孩子变成了遍历一个结点数组。
vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> ans;queue<Node*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();vector<int> vec;while(size--){Node* cur = que.front();vec.push_back(cur->val);que.pop();for(auto it = cur->children.begin(); it != cur->children.end(); it++){que.push(*it);}}ans.push_back(vec);}return ans;}
LeetCode 515. 在每个树行中找最大值
之前做过类似找最大最小值的题目,这里令对比对象初始化为INT_MIN
。
vector<int> largestValues(TreeNode* root) {vector<int> ans;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();int temp = INT_MIN;while(size--){TreeNode* node = que.front();temp = node->val > temp ? node->val : temp;que.pop();if(node->left) que.push(node->left);if(node->right) que.push(node->right);}ans.push_back(temp);}return ans;}
LeetCode 116. 填充每个节点的下一个右侧节点指针
本题就是在遍历时加一个判断,如果为本层最后一个结点,使其指向NULL
即可。
Node* connect(Node* root) {queue<Node*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();while(size--){Node* cur = que.front();que.pop();if(size != 0){cur->next = que.front();}else{cur->next = NULL;}if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return root;}
LeetCode 104. 二叉树的最大深度
这里要知道二叉树深度的概念,以及高度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
二叉树的高度是表示当前结点所在的位置。比如二叉树最下方的叶子结点的高度为1,根节点的高度与深度相同。
采用层序遍历,在一层结束后,depth++
即可。
int maxDepth(TreeNode* root) {int ans = 0;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();while(size--){TreeNode* cur = que.front();que.pop();if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}ans++;}return ans;}
111. 二叉树的最小深度
当左右孩子都为空的时候,才说明遍历到最低点了,如果其中一个孩子为空则不是最低点。所以当找到左右孩子都为空的结点时,直接返回结果即可。
int minDepth(TreeNode* root) {int min = 0;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();min++;while(size--){TreeNode* cur = que.front();que.pop();//找到即返回if(cur->left == NULL && cur->right == NULL) return min;if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return min;}
LeetCode 226. 翻转二叉树
本题也是有很多解法,递归迭代都可以实现。
递归:
递归上来还是三部曲:- 输入就是当前需要反转的结点,输出就是反转过后的结点。
- 终止条件是空结点时,结束本层递归
- 递归函数体就是反转左右结点
代码如下:
TreeNode* invertTree(TreeNode* root) {if (root == NULL) return root;swap(root->left, root->right); // 中invertTree(root->left); // 左invertTree(root->right); // 右return root; }
后序递归的话只需要把反转逻辑放在最后即可。
如果是中序遍历,会将一个结点反转两次,所以不推荐中序,中序需要把代码写成这样:invertTree(root->left); // 左swap(root->left, root->right); // 中invertTree(root->left); // 右
我需要反转的右结点实际上是经过反转后的左节点,所以反转两次left。
迭代
迭代其实也很简单,在遍历的过程中添加一个swap
完成反转,代码如下:TreeNode* invertTree(TreeNode* root) {if(root == NULL) return root;stack<TreeNode*> st;st.push(root);while(!st.empty()){TreeNode* cur = st.top();st.pop();swap(cur->left,cur->right); //中if(cur->right) st.push(cur->right); //右if(cur->left) st.push(cur->left); //左}return root;}
这里只给出前序迭代的代码,后序类似。
迭代的统一写法(前序):
TreeNode* invertTree(TreeNode* root) {stack<TreeNode*> st;if(root == NULL) return root;st.push(root);while(!st.empty()){TreeNode* cur = st.top();if(cur != NULL){st.pop();if(cur->right) st.push(cur->right);if(cur->left) st.push(cur->left);st.push(cur);st.push(NULL);}else{st.pop();cur = st.top();swap(cur->left, cur->right);st.pop();}}return root; }
还是一样,在处理中间结点的时候
swap
一下。层序
最后是层序,层序这题也可以做,相同的思路,一样的味道。
代码如下:TreeNode* invertTree(TreeNode* root) {queue<TreeNode*> que;if(root == NULL) return root;que.push(root);while(!que.empty()){int size = que.size();while(size--){TreeNode* cur = que.front();que.pop();swap(cur->left,cur->right);if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return root; }
LeetCode 101. 对称二叉树
这题leetcode上给出的是简单难度,实际上思路和代码复杂度上怎么说也得是个中等难度。
首先需要搞清楚几种情况:
- 左节点为空,右节点不为空,不对称
- 左不为空,右为空,不对称
- 左右都为空,对称
- 左右都不为空且值不等,不对称
- 左右都不为空且值相等,对称
然后要清楚对比的是二叉树两侧的结点,分为内侧和外侧。下面给出卡哥的图:
这样看比较清晰。
最后看一颗二叉树是否是对称二叉树,实际上是对比这颗树的左右子树,也就是对两棵子树同时进行遍历。
接下来就是考虑使用的遍历方式和遍历顺序,首先是递归遍历。
递归
递归的三要素:- 输入输出:输入应该是两侧的两个结点left和right进行对比,所以输入是两个参数,输出即是否对称,为
bool
- 终止条件:不对称即
false
,直接退出递归 - 递归函数体
递归代码如下:
bool compare(TreeNode* left , TreeNode* right){if(left != NULL && right == NULL) return false;else if(left == NULL && right != NULL) return false;else if(left == NULL && right == NULL) return true;else if(left->val != right->val) return false;//else return compare(left->left, right->right) && compare(left->right, right->left);bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)return isSame; }
先把外侧的结点处理完成,再处理内侧结点,也就是代码中的
outside
和inside
。left->left
就是左子树继续往外走,right->right
就是右子树继续往外走。最后返回值必须两者都是true
才说明是对称。
其次注意if和else if语句中的顺序,首先需要把有可能出现空结点的情况讨论完,再去讨论不是空结点的情况,否则会出现访问空结点的错误。- 输入输出:输入应该是两侧的两个结点left和right进行对比,所以输入是两个参数,输出即是否对称,为
迭代
迭代遍历首先还是要模拟一下入栈和出栈的过程,只有把过程搞明白了,才能写出正确的代码。直接看代码以及注释:bool isSymmetric(TreeNode* root) {queue<TreeNode*> que;//因为是同时遍历左右子树,所以要先把根节点的左右孩子压入que.push(root->left);que.push(root->right);while(!que.empty()){//取出结点进行对比。先压入再取出处理也是迭代中必须的手法TreeNode* l = que.front();que.pop();TreeNode* r = que.front();que.pop();if(l == NULL && r == NULL) continue; //首先处理都为空的情况,直接进入下一次循环//再处理不对称的情况if(l == NULL && r != NULL) return false;else if(l != NULL && r == NULL) return false;else if(l->val != r->val) return false;//最后按照顺序将当前结点的子结点压入栈中que.push(l->left);que.push(r->right);que.push(l->right);que.push(r->left);}return true; }
迭代相对于递归的写法更复杂一些,我认为将结点成对的入栈,再成对的取出进行对比是本题的核心思想。
最后
因为二叉树是面试中常考的数据结构,对二叉树的处理也是手撕代码中出现频率较高的,需要熟练掌握,所以要经常回来复习一下!
代码随想录第十五天 二叉树层序遍历 226、101相关推荐
- 代码随想录第二十五天|组合、电话号码的字母组合
代码随想录第二十五天|216.17不熟 Leetcode 216. 组合总和 III Leetcode 17. 电话号码的字母组合 Leetcode 216. 组合总和 III 题目链接: 组合总和 ...
- 代码随想录算法训练营第十五天| 102层序遍历、226.翻转二叉树、101. 对称二叉树
层序遍历 参考文章:代码随想录 解题思路: 层序遍历一个二叉树.就是从左到右一层一层的去遍历二叉树.这种遍历的方式和我们之前讲过的都不太一样. 需要借用一个辅助数据结构即队列来实现,队列先进先出,符合 ...
- 代码随想录第二十五天|261.组合总和、17.电话号码的字母组合
261.组合总和 找出所有相加之和为 n 的 k 个数的组合.组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字. class Solution { private:vector& ...
- 代码随想录【day 14 二叉树】| 层序遍历 226.翻转二叉树 101.对称二叉树
代码随想录[day 14 二叉树]| 层序遍历 226.翻转二叉树 101.对称二叉树 层序遍历 卡哥文解 视频讲解 题目链接:102.二叉树的层序遍历 解题思路 代码实现 题目链接:107.二叉树的 ...
- 【LeetCode】专题一 二叉树层序遍历
二叉树层序遍历 在本文中,我将会选取LeetCode上二叉树层序遍历的多道例题,并给出解答,通过多道题我们就可以发现,二叉树的层序遍历并不复杂,并且有着共通点. 102. 二叉树的层序遍历 给你二叉树 ...
- DS-第五章-二叉树的遍历
数据结构二叉树遍历总结⭐⭐⭐ DS-第五章-二叉树的遍历⭐⭐⭐ 数据结构二叉树遍历总结⭐⭐⭐ 二叉树的概念 遍历 习题分析与代码 二叉树的遍历与线索二叉树 先序遍历 递归先序遍历 非递归算法 中序遍历 ...
- 二叉树层序遍历_求二叉树的层序遍历
题目描述 给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, 该二叉树层序遍历的结果是 [ [3], [9,20], ...
- 牛客-二叉树层序遍历
牛客-二叉树层序遍历 #include <stdio.h> #include <queue> #include <stack> #include <math. ...
- 数据结构:二叉树层序遍历和判断是否为完全二叉树
层序遍历 从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第二层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的节点的过程. while(队列!=NULL) ...
- 二叉树层序遍历分层[递归迭代两种思想+三种解法]
层序遍历分层的递归迭代解法 前言 一.二叉树层序遍历分层 二.递归与迭代 总结 参考文献 前言 层序遍历作为二叉树遍历的基本遍历,一般来说只能用迭代来解.但是分层输出则既可用迭代,又可配合level用 ...
最新文章
- 调侃 -- 刚入职时的单纯
- ifndef/define/endif——主要目的是防止头文件的重复包含和编译
- 实例演示使用HiBench对Hadoop集群进行基准测试
- oracle usehash,/*+use_hash(t1 t2)*/的神奇
- 2019-03-12-算法-进化(合并两个有序数组)
- python集合用法_Python 集合(Set)
- ios开发网络学习:一:NSURLConnection发送GET,POST请求
- BDTC 2019 | 七个开发者能干多大的事?​
- xcode swift_CocoaPods Swift XCode教程
- AndroidGUI24:TabHost常用技巧
- windows 下安装securecrt 绿色版
- 计算机科学 院士 高校,快报!第5轮学科评估计算机科学与技术评委会名单,看有谁上榜了...
- 疑难杂症、易混淆、易遗忘的知识点记录
- 华为路由器学习指南_BGP_路由反射器与联盟
- SMART-DOC使用总结
- 计算机视觉算法——基于Anchor Free的目标检测网络总结
- linux wps2016_2016年十大Linux新闻报道
- 计算机视觉学习 BOW模型图像搜索
- Vim实用技巧高清完整版PDF中文
- 分享130个ASP源码,总有一款适合您
热门文章
- Neo4j之导入CSV大文件 periodic commit
- python笔记之json报错
- js 格式化prettier配置_Prettier 代码格式化插件 -- 配置翻译
- 苹果计算机做视频教程,Mac版Final Cut Pro x使用技巧及视频教程
- 一看就懂的保姆级教程:open vn设置 (亲测通过)
- 山东理工大学ACM平台题答案关于C语言 1228 两数组最短距离
- DeFi新玩法丨一文教你玩转NFT碎片化协议Fractional
- link rel=canonical概念和用法(增加页面权重,利于排名)
- 政府大数据服务,跑马圈地正当时
- PDF文件有密码怎么取消加密