我要打六个——打爆层序遍历
在此非常感谢“代码随想录”的通俗易懂的总结,直接感觉打通层序遍历的任督二脉,可以一口气打六个!
(致敬叶师傅和李小龙)
“我不害怕曾经练过一万种踢法的人,但我害怕一种踢法练过一万次的人”(by 叶师傅的徒弟Bruce Lee)
今天是2021年3月14日,在这个龙抬头和白色情人节的“双节”日子里,第一次一口气刷了6道中等难度Leetcode题(主要是层序遍历),一个字——爽,加油,冲冲冲!
一、总体思路:
层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们最常见的前中后序遍历都不太一样。
需要借用一个辅助数据结构即队列来实现,「队列先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
「而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。」
二、具体题目
题目1:102. 二叉树的层序遍历
题目描述:
给你一个二叉树,请你返回其按层序遍历得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
C++代码
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
vector<vector<int>> result;
if(root) que.push(root);
while(!que.empty()){
int size=que.size(); // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
vector<int> vec;
for(int i=0;i<size;++i){
TreeNode* cur=que.front();
que.pop();
if(cur) vec.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(vec);
}
return result;
}
};
题目2:107. 二叉树的层序遍历 II
题目描述:
给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7]
C++代码:
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> que;
vector<vector<int>> result;
if(root) que.push(root);
while(!que.empty()){
int size=que.size();
vector<int> vec;
for(int i=0;i<size;++i){
TreeNode* cur=que.front();
que.pop();
if(cur) vec.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(vec);
}
reverse(result.begin(),result.end());
return result;
}
};
题目3:199. 二叉树的右视图
题目描述:
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
C++代码:
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode*> que;
vector<int> result;
if(root) que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;++i){
TreeNode* cur=que.front();
que.pop();
if((i==size-1) && (cur)) result.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return result;
}
};
题目4:637. 二叉树的层平均值
题目描述:
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
示例:
C++代码:
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*> que;
vector<double> result;
if(root) que.push(root);
while(!que.empty()){
int size=que.size();
double levelsum=0.0;
for(int i=0;i<size;++i){
TreeNode* cur=que.front();
que.pop();
if(cur) levelsum+=cur->val;
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(levelsum/size);
}
return result;
}
};
题目5:429. N 叉树的层序遍历
题目描述:
给定一个 N 叉树,返回其节点值的层序遍历。
(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[[1],[3,2,4],[5,6]]
示例 2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]
C++代码:
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
queue<Node*> que;
vector<vector<int>> result;
if(root) que.push(root);
while(!que.empty()){
int size=que.size(); // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
vector<int> vec;
for(int i=0;i<size;++i){
Node* cur=que.front();
que.pop();
if(cur) vec.push_back(cur->val);
for(int j=0;j<cur->children.size();++j){
if(cur->children[j]){
que.push(cur->children[j]);
}
}
}
result.push_back(vec);
}
return result;
}
};
题目6:515. 在每个树行中找最大值
题目描述:
您需要在二叉树的每一行中找到最大的值。
示例:
C++代码:
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
queue<TreeNode*> que;
if(root) que.push(root);
vector<int> result;
while(!que.empty()){
int size=que.size();
int levelmax=que.front()->val;
// int levelmax=INT_MIN;
for(int i=0;i<size;++i){
TreeNode* cur=que.front();
que.pop();
if(cur->val>levelmax) levelmax=cur->val;
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(levelmax);
}
return result;
}
};
总结
二叉树
前中后序遍历统称为——深度优先遍历
层序遍历即为——广度优先遍历
二叉树的层序遍历,就是图论中的广度优先搜索在二叉树中的应用,需要借助队列来实现(队列的应用)。
学会二叉树的层序遍历,可以一口气做完Leetcode上六道题目:
102.二叉树的层序遍历
107.二叉树的层次遍历II
199.二叉树的右视图
637.二叉树的层平均值
589.N叉树的前序遍历
515.在每个树行中找最大值
思维:对于层序遍历要直接想起队列方法!
层序遍历只要掌握基本写法(也就是框架模板),剩下的就是在二叉树每一行遍历的时候做做逻辑修改。
Notes:
1.对于N叉树,children是一个类似于节点Node列表的东西,需要循环children.size()次迭代children[i]入队!
2.之后求最大值直接把max初始化为INT_MIN,求最小值时直接把min初始化为INT_MAX,这样就会避免最后输出值为最开始初始化的0值
INT_MIN在标准头文件limits.h中定义。
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
在C/C++语言中,不能够直接使用-2147483648来代替最小负数,因为这不是一个数字,而是一个表达式。表达式的意思是对整数21473648取负,但是2147483648已经溢出了int的上限,所以定义为(-INT_MAX -1)
C中int类型是32位的,范围是-2147483648到2147483647
(1)最轻微的上溢是INT_MAX + 1 :结果是 INT_MIN
(2)最严重的上溢是INT_MAX + INT_MAX :结果是-2
(3)最轻微的下溢是INT_MIN - 1:结果是是INT_MAX
(4)最严重的下溢是INT_MIN + INT_MIN:结果是0
欢迎大家扫码关注本人公众号:编程复盘与思考随笔
(关注后可以免费获得本人在csdn发布的资源源码)
公众号主要记录编程和刷题时的总结复盘笔记和心得!并且分享读书、工作、生活中的一些思考感悟!