题目一 剑指 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. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术的更多相关文章

  1. 【Java】 剑指offer(32) 从上往下打印二叉树

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺 ...

  2. 二维数组的查找,刷题成功——剑指Offer

    今天又做了一道题目,通过啦,欧耶! https://www.nowcoder.net/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqI ...

  3. Leetcode刷题记录 剑指offer

    面试题3:数组中重复数字 # 使用set,时间复杂度O(n),空间复杂度O(n)class Solution(object): def findRepeatNumber(self, nums): &q ...

  4. #刷题记录--剑指 Offer 07. 重建二叉树

    输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字. 抓住一点,通过递归进行节点创建时,是按照 前序遍历数组 进行创建的. 根节点,根节点的左 ...

  5. 剑指offer——32从上到下打印二叉树

    题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印.   题解: 就是简单的层序遍历 class Solution { public: vector<int> PrintFro ...

  6. 剑指 Offer 32 - I. 从上到下打印二叉树 + 层次遍历二叉树

    剑指 Offer 32 - I. 从上到下打印二叉树 Offer_32_1 题目描述 解题思路 这题属于简单题,考察的是我们对二叉树以及层次遍历的方法. 这里只需要使用简单的队列即可完成二叉树的层次遍 ...

  7. 剑指 Offer 32 - III. 从上到下打印二叉树 III

    剑指 Offer 32 - III. 从上到下打印二叉树 III 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印, ...

  8. 剑指 Offer 32 - I. 从上到下打印二叉树

    剑指 Offer 32 - I. 从上到下打印二叉树 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印. 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 ...

  9. 剑指 Offer 32 - III. 从上到下打印二叉树 III + 双端队列使用 + 蛇形打印层次遍历序列 + 正倒序输出

    剑指 Offer 32 - III. 从上到下打印二叉树 III Offer_32_3 题目详情 题解分析 本题我想的比较复杂,其实题目的要求只是需要遍历的结果逆序和正序交替,这个其实可以使用Coll ...

随机推荐

  1. Snort 入侵检测系统

    Snort 入侵检测系统 一.实验目的 1.掌握snort IDS工作原理 2.应用snort 三种方式工作 二.实验环境 系统环境:Windows环境, kali环境 三.实验原理 1.snort ...

  2. Linux的命令行基础

    1.对于全局配置文件和用户配置文件的认识 全局配置都存储在etc目录下,如/etc/profile文件,/etc/bashrc文件以及/etc/profile.d/目录下的.sh文件 用户配置都存储在 ...

  3. ciscn_2019_s_3

    拿到题目例行检查 64位程序开启了nx保护,将程序放入ida 看到没有system函数第一时间想到的就是泄露libc来做,后来才知道是我学识尚浅,需要用execve函数来做 进入main发现跳转到vu ...

  4. [BUUCTF]REVERSE——[SUCTF2019]SignIn

    [SUCTF2019]SignIn 附件 步骤: 无壳,64位ida载入 程序调用了 __gmpz_init_set_str 函数,这是一个 GNU 高精度算法库,在RSA加密中见过几次,加上6553 ...

  5. LuoguP7892 『JROI-3』R.I.P. 题解

    Update \(\texttt{2021.10.11}\) 修改了一处公式错误,麻烦管理重新审核一下这篇已审核通过文章. Content 你在一个无限大的格子平面上,并且有 \(m\) 个长度为 \ ...

  6. CF1494B Berland Crossword 题解

    Content 有一种叫做 Berland crossword 的拼图游戏.这个拼图由 \(n\) 行 \(n\) 列组成,你可以将里面的一些格子涂成黑色.现在给出 \(T\) 个这样的拼图,每个拼图 ...

  7. 【LeetCode】855. Exam Room 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/exam-roo ...

  8. 【LeetCode】868. Binary Gap 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 线性扫描 日期 题目地址:https://leetc ...

  9. leetcode1260二维网络迁移

    题目 n*m的矩阵,一个整数k,移动矩阵k次.每次移动的操作为: 向右移动(最后一列移动到第一列) 之后,第一列向下移动. 1<=N.M<=50 0<=k<=100 题解 思考 ...

  10. Chapter 1 A Definition of Causal Effect

    目录 1.1 Individual casual effects 1.2 Average casual effects 1.5 Causation versus association Hern\(\ ...