力扣日记:【二叉树篇】二叉树的层序遍历
日期:2023.11.7
参考:代码随想录、力扣
102. 二叉树的层序遍历
题目描述
难度:中等
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:
输入:root = [1]
输出:[[1]]
示例 3:
输入:root = []
输出:[]
提示:
- 树中节点数目在范围 [0, 2000] 内
- -1000 <= Node.val <= 1000
题解
cpp ver
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
#define SOLUTION 2
#if SOLUTION == 1 // 迭代遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
// 层序遍历需要将二叉树按层保存在一个二维数组中
// 思路:
// 1. 首先记录队列长度size,即需要连续弹出的元素个数(某一层元素的个数)
// 2. 每弹出一个元素后,将元素的左右节点加入队列
// 3. 在连续弹出size个元素后,重新回到1
queue<TreeNode*> q;
vector<vector<int>> result;
if (root != NULL) q.push(root);
while (!q.empty()) {
int size = q.size(); // 首先记录队列长度,即当前层元素个数
vector<int> res; // 存放当前层元素
while (size--) {
TreeNode* node = q.front(); // 弹出元素
q.pop();
res.push_back(node->val);
// 将左右节点加入队列
if (node->left != NULL) q.push(node->left);
if (node->right != NULL) q.push(node->right);
}
// 将当前层元素加入数组
result.push_back(res);
}
return result;
}
};
#elif SOLUTION == 2 // 递归遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if (root == NULL) return result;
int depth = 0;
order(root, result, depth);
return result;
}
void order(TreeNode* cur, vector<vector<int>>& result, int depth) {
// 输入参数:当前节点, 结果集指针(需要为指针!), 当前节点所在层数
// 终止条件:当前节点为空
if (cur == NULL) return;
// 处理逻辑:
// 如果结果集大小(层数)与所需深度(depth从0开始)相等(即少一层),说明结果集需要增加一层来存放当前节点
if (result.size() == depth) result.push_back(vector<int>());
// 将当前节点加入结果集对应层(层数在参数已经指定)
result[depth].push_back(cur->val);
// 递归:将左节点当作根节点重复上述逻辑
order(cur->left, result, depth + 1); // depth + 1,表示第一个参数指定的节点所在层数为depth+1
order(cur->right, result, depth + 1); // 注意cur->right的深度与cur->left一样,不会受上面的递归影响
}
};
#endif
go ver
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func levelOrder(root *TreeNode) [][]int {
// go中的队列可通过list实现
/*
import "container/list"
// 创建一个新的双向链表
queue := list.New()
// 入队操作
queue.PushBack(1)
// 出队操作
if queue.Len() > 0 {
front := queue.Front()
queue.Remove(front)
fmt.Println("出队元素:", front.Value)
}
*/
queue := list.New()
res := [][]int{}
if root != nil {
queue.PushBack(root)
}
for queue.Len() > 0 {
// 记录当前队列长度
size := queue.Len()
vec := []int{}
for size > 0 {
// 弹出并写入结果
front := queue.Front()
node := queue.Remove(front).(*TreeNode) // 存进list之后类型会变为*list.Element,要转换为*TreeNode
vec = append(vec, node.Val)
// 左右节点入队列
if node.Left != nil {
queue.PushBack(node.Left)
}
if node.Right != nil {
queue.PushBack(node.Right)
}
size -= 1
}
res = append(res, vec)
}
return res
}
复杂度
时间复杂度:
空间复杂度:
思路总结
- 层序遍历写法较固定,可作为模板
- 1.首先记录队列长度size,即需要连续弹出的元素个数(某一层元素的个数)
- 2.每弹出一个元素后,将元素的左右节点加入队列
- 3.在连续弹出size个元素后,重新回到1
- 对于递归写法:
- 输入参数:当前节点, 结果集指针(需要为指针!), 当前节点所在层数
- 终止条件:当前节点为空
- 处理逻辑:
- 如果结果集大小(层数)与所需深度(depth从0开始)相等(即少一层),说明结果集需要增加一层来存放当前节点
- 将当前节点加入结果集对应层(层数在参数已经指定)
- 递归:分别将左右节点当作根节点重复上述逻辑