【Warrior刷题笔记】剑指offer 32. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术
题目一 剑指 Offer 32 - I. 从上到下打印二叉树
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/
1.描述
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
2.示例
- 示例 1:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回:
[3,9,20,15,7]
解法一 广度优先遍历+辅助队列
解题思路
看到题不难想到最简单的办法就是借助一个队列,对二叉树进行广度优先遍历。
1.如果根节点为空,直接返回空数组,否则入队根节点;
2.将队头节点值加入答案数组;
3.入队队头节点的非空子节点,将队头节点出队。
4.重复2,3过程直到队列为空。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> levelOrder(TreeNode* root) {
vector<int> ans;//存储答案
if(!root) return ans;//如果根节点为空,返回空答案数组
queue<TreeNode*> q;//辅助队列
q.push(root);//根节点入队
while(!q.empty()){//只要队列不为空
ans.push_back(q.front()->val);//将队头节点值加入答案数组
//入队队头节点的非空子节点
if(q.front()->left) q.push(q.front()->left);
if(q.front()->right) q.push(q.front()->right);
q.pop();//将队头节点出队
}
return ans;//返回答案
}
};
复杂度分析
时间复杂度: O(m)。m二叉树节点数,遍历整棵二叉树需要O(m)时间。
空间复杂度: O(m)。存储答案和使用辅助队列的空间消耗。
解法二 深度优先搜索+辅助数组
解题思路
除了解法一较为直观的广度优先搜索外,我们也可以使用深度优先搜索+辅助二维数组解决本题。
具体的,我们对二叉树进行深度优先搜索,同时维护一个层数level,初始时level为0。每进入一层递归,也即从当前节点遍历孩子节点时,层数就加一,然后通过层数作为下标访问二维数组将节点值加入对应层的一维数组,最后再将二维数组按层捋直即为最终答案。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> levelOrder(TreeNode* root) {
vector<int> ans;//存储答案
if(!root) return ans;//如果根节点为空,返回空数组
vector<vector<int>> aid;//辅助数组
dfs(root, 0, aid);//深度优先遍历
for(auto a : aid) ans.insert(ans.end(), a.begin(), a.end());//将二维数组按层捋直
return ans; //返回答案
}
void dfs(TreeNode* root, int level, vector<vector<int>>& aid){
if(!root) return;//如果节点为空,返回
if(aid.size()<=level){//如果该层数组还未创建,创建之
vector<int> temp;
aid.push_back(temp);
}
aid[level].push_back(root->val);//将节点值加入对应层数组
dfs(root->left, level+1, aid);//遍历左子节点,同时level+1
dfs(root->right, level+1, aid);//遍历右子节点,同时level+1
}
};
复杂度分析
时间复杂度: O(m)。递归以及把二维数组捋直的时间消耗
空间复杂度: O(m)。递归以及辅助数组、答案数组的空间消耗。
题目二 剑指 Offer 32 - II. 从上到下打印二叉树 II
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/
1.描述
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
2.示例
- 示例 1:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
解法一 广度优先搜索+辅助队列
解题思路
参考题目一,我们可以写出广度优先搜索+辅助队列的版本。
不过略有不同的是,我们需要选择合适的方式进行分层。这里使用两个额外变量count和size进行分层操作,对每一层,size为层大小,初始时为1,即只有根节点的时候队列的大小。每记录一个节点,count值加一,当count等于size时,表示当前层已遍历完毕,则更新层大小,重置count为0。
1.如果根节点为空,直接返回空数组,否则入队根节点;
2.将队头节点值加入答案数组;
3.入队队头节点的非空子节点,将队头节点出队;
4.将count加一,若count等于size,则更新size,并重置count为0;
5.重复2,3,4过程直到队列为空。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;//存储答案
if(!root) return ans;//如果根节点为空,返回空数组
queue<TreeNode*> q;//辅助队列
q.push(root);//入队根节点
int size = q.size(), count = 0;//初始化size和count
vector<int> temp;//辅助数组
while(!q.empty()){//只要队列不为空
temp.push_back(q.front()->val);//记录队头节点值
//入队队头节点的非空子节点
if(q.front()->left) q.push(q.front()->left);
if(q.front()->right) q.push(q.front()->right);
q.pop();//出队队头节点
++count;//将count+1
if(count == size){//若count==size,表示当前层已记录完毕
ans.push_back(temp);//将temp加入答案数组
temp.clear();//清空temp
count = 0;//重置count为0
size = q.size();//更新size
}
}
return ans;//返回答案
}
};
复杂度分析
时间复杂度: O(m)。m为二叉树节点数,遍历整棵二叉树需要O(m)时间。
空间复杂度: O(m)。辅助队列,答案数组,辅助数组的空间消耗。
解法二 深度优先搜索+辅助数组
解题思路
除了解法一较为直观的广度优先搜索外,我们也可以使用深度优先搜索+辅助二维数组解决本题。
具体的,我们对二叉树进行深度优先搜索,同时维护一个层数level,初始时level为0。每进入一层递归,也即从当前节点遍历孩子节点时,层数就加一,然后通过层数作为下标访问二维数组将节点值加入对应层的一维数组,遍历完成后即为最终答案。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;//存储答案
if(!root) return ans;//如果根节点为空,返回空数组
dfs(root, 0, ans);//深度优先遍历
return ans;//返回答案
}
void dfs(TreeNode* root, int level, vector<vector<int>>& aid){//深度优先遍历
if(!root) return;//如果节点为空,直接返回
if(aid.size()<=level){//如果当前层数组还未创建,创建之
vector<int> temp;
aid.push_back(temp);
}
aid[level].push_back(root->val);//存入当前节点值到对应层
dfs(root->left, level+1, aid);//遍历左孩子,层数加一
dfs(root->right, level+1, aid);//遍历右孩子,层数加一
}
};
复杂度分析
时间复杂度: O(m)。遍历二叉树的时间消耗。
空间复杂度: O(m)。存储答案和递归的栈空间消耗。
题目三 剑指 Offer 32 - III. 从上到下打印二叉树 III
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/
1.描述
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
2.示例
- 示例 1:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]
解法一 广度优先搜索+辅助队列
解题思路
参考题目二,我们可以写出广度优先搜索+辅助队列的版本。
我们需要选择合适的方式进行分层。这里使用两个额外变量count和size进行分层操作,对每一层,size为层大小,初始时为1,即只有根节点的时候队列的大小。每记录一个节点,count值加一,当count等于size时,表示当前层已遍历完毕,则更新层大小,重置count为0。不过略有不同的是,我们需要在遍历完毕后对结果数组进行处理,也即翻转偶数层数组。处理完毕后即为答案。
1.如果根节点为空,直接返回空数组,否则入队根节点;
2.将队头节点值加入答案数组;
3.入队队头节点的非空子节点,将队头节点出队;
4.将count加一,若count等于size,则更新size,并重置count为0;
5.重复2,3,4过程直到队列为空;
6.翻转偶数层结果数组。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;//存储答案
if(!root) return ans;//如果根节点为空,返回空数组
queue<TreeNode*> q;//辅助队列
q.push(root);//入队根节点
int size = q.size(), count = 0;//初始化size和count
vector<int> temp;//辅助数组
while(!q.empty()){//只要队列不为空
temp.push_back(q.front()->val);//记录队头节点值
//入队队头节点的非空子节点
if(q.front()->left) q.push(q.front()->left);
if(q.front()->right) q.push(q.front()->right);
q.pop();//出队队头节点
++count;//将count+1
if(count == size){//若count==size,表示当前层已记录完毕
ans.push_back(temp);//将temp加入答案数组
temp.clear();//清空temp
count = 0;//重置count为0
size = q.size();//更新size
}
}
for(int i = 0; i < m; ++i) if(i%2!=0) reverse(ans[i].begin(), ans[i].end());//翻转偶数层
return ans;//返回答案
}
};
复杂度分析
时间复杂度: O(m)。m为二叉树节点数,遍历整棵二叉树和翻转偶数层需要O(m)时间。
空间复杂度: O(m)。辅助队列,答案数组,辅助数组的空间消耗。
解法二 深度优先遍历+辅助数组
解题思路
这里也提供深度优先遍历的版本。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;//存储答案
if(!root) return ans;//如果根节点为空,返回空数组
dfs(root, 0, ans);//深度优先遍历
for(int i = 0; i < m; ++i) if(i%2!=0) reverse(ans[i].begin(), ans[i].end());//翻转偶数层
return ans;//返回答案
}
void dfs(TreeNode* root, int level, vector<vector<int>>& aid){//深度优先遍历
if(!root) return;//如果节点为空,直接返回
if(aid.size()<=level){//如果当前层数组还未创建,创建之
vector<int> temp;
aid.push_back(temp);
}
aid[level].push_back(root->val);//存入当前节点值到对应层
dfs(root->left, level+1, aid);//遍历左孩子,层数加一
dfs(root->right, level+1, aid);//遍历右孩子,层数加一
}
};
复杂度分析
时间复杂度: O(m)。遍历二叉树和翻转偶数层的时间消耗。
空间复杂度: O(m)。存储答案和递归的栈空间消耗。
一般说来,广度优先遍历更直观,但是代码较长;而深度优先遍历代码简洁,但是较难理解。要多用多练,以掌握之。
更多知识内容分享:
博客园个人主页https://home.cnblogs.com/u/newCoderTheWarrior
力扣个人主页https://leetcode-cn.com/profile/articles/

【Warrior刷题笔记】剑指offer 32. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术的更多相关文章
- 【Java】 剑指offer(32) 从上往下打印二叉树
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺 ...
- 二维数组的查找,刷题成功——剑指Offer
今天又做了一道题目,通过啦,欧耶! https://www.nowcoder.net/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqI ...
- Leetcode刷题记录 剑指offer
面试题3:数组中重复数字 # 使用set,时间复杂度O(n),空间复杂度O(n)class Solution(object): def findRepeatNumber(self, nums): &q ...
- #刷题记录--剑指 Offer 07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字. 抓住一点,通过递归进行节点创建时,是按照 前序遍历数组 进行创建的. 根节点,根节点的左 ...
- 剑指offer——32从上到下打印二叉树
题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 题解: 就是简单的层序遍历 class Solution { public: vector<int> PrintFro ...
- 剑指 Offer 32 - I. 从上到下打印二叉树 + 层次遍历二叉树
剑指 Offer 32 - I. 从上到下打印二叉树 Offer_32_1 题目描述 解题思路 这题属于简单题,考察的是我们对二叉树以及层次遍历的方法. 这里只需要使用简单的队列即可完成二叉树的层次遍 ...
- 剑指 Offer 32 - III. 从上到下打印二叉树 III
剑指 Offer 32 - III. 从上到下打印二叉树 III 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印, ...
- 剑指 Offer 32 - I. 从上到下打印二叉树
剑指 Offer 32 - I. 从上到下打印二叉树 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印. 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 ...
- 剑指 Offer 32 - III. 从上到下打印二叉树 III + 双端队列使用 + 蛇形打印层次遍历序列 + 正倒序输出
剑指 Offer 32 - III. 从上到下打印二叉树 III Offer_32_3 题目详情 题解分析 本题我想的比较复杂,其实题目的要求只是需要遍历的结果逆序和正序交替,这个其实可以使用Coll ...
随机推荐
- JSP九大内置对象及四个作用域详解
一共有九大内置对象: request.response.out.session.application.pageContext.page.config.exception 内置对象(又叫隐含对象),就 ...
- 20 个 .NET 6 新增的 API
DateOnly & TimeOnly .NET 6 引入了两种期待已久的类型 - DateOnly 和 TimeOnly, 它们分别代表DateTime的日期和时间部分. DateOnly ...
- 替换资源(Project)
<Project2016 企业项目管理实践>张会斌 董方好 编著 还是那个熟悉的某吃货甲,一天之内给他分配了9.6个工时的吃量,这太不厚道了哈,人家一个人又要开吃又要喝汤,这怎么吃得消呢? ...
- AtCoder Beginner Contest 148 题解
目录 AtCoder Beginner Contest 148 题解 前言 A - Round One 题意 做法 程序 B - Strings with the Same Length 题意 做法 ...
- xfs文件系统修复方法https://blog.csdn.net/yuanfang_way/article/details/78700089
首先尝试mount和umount文件系统,以便重放日志,修复文件系统,如果不行,再进行如下操作. 1.检查文件系统:先确保umount xfs_check /dev/sdd(盘符); echo $? ...
- 点击DIV触发其他元素的点击事件(案例:点击type="radio" 的input 标签外层DIV,触发内部单选点击选中事件)
方法一: 直接用找到对应dom元素调用.click()方法 $('.user_content').click(function(){ $(this).children()[0].click(); // ...
- SpringBoot项目使用Caffeine本地缓存
环境配置:(或以上版本,必须) JDK 版本:1.8 Caffeine 版本:2.8.0SpringBoot 版本:2.2.2.RELEASE 也可以不与SpringBoot结合 1.添加maven ...
- UDP&串口调试助手用法(3)
发送参数配置 下面以 UDP 通道为例介绍 发送数据配置 概览 选择数据源 文件: 选择发送的文件 源码: 自己手动键入发送数据,默认输入的为16进制数据, 定时器发送周期 单位为毫秒. 发送帧计数 ...
- 【LeetCode】310. Minimum Height Trees 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS 相似题目 参考资料 日期 题目地址:http ...
- Beautiful Walls
[1553] Beautiful Walls 时间限制: 1000 ms 内存限制: 65535 K 问题描述 To simplify the building process, XadillaX b ...