目录
二叉树的层序遍历
前言
102.二叉树的层序遍历
107.二叉树的层次遍历 II
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的层序遍历
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针II
104.二叉树的最大深度
111.二叉树的最小深度
226.翻转二叉树
思路分析
递归法实现
前序遍历
后序遍历
迭代法实现
广度优先遍历
101. 对称二叉树
思路分析
递归实现
总结
层序遍历一个二叉树,就是从左到右一层层地去遍历二叉树。需要借用队列来实现,队列先进先出,符合一层一层遍历的逻辑,而栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
以下是十道应用层序遍历的题目:
题目链接https://leetcode.cn/problems/binary-tree-level-order-traversal/description/
/**
* 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) {}
* };
*/
class Solution {
public:
vector> levelOrder(TreeNode* root) {
queue que;
vector> result;
if (root == NULL) return result;
que.push(root);
while (!que.empty()){
//进入下面的循环后que.size()会不断变化,要在开始就固定size的大小
int size = que.size();
vector vec;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(vec);
}
return result;
}
};
这份代码也可以作为二叉树层序遍历的模板!
题目链接https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/description/
/**
* 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) {}
* };
*/
class Solution {
public:
vector> levelOrderBottom(TreeNode* root) {
queue que;
vector> result;
if (root == NULL) return result;
que.push(root);
while (!que.empty()){
int size = que.size();
vector vec;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(vec);
}
reverse(result.begin(), result.end());
return result;
}
};
本题要求返回二叉树自底向上的层次遍历,只需要将前例模板中的结果数组result进行反转即可。
题目链接https://leetcode.cn/problems/binary-tree-right-side-view/
/**
* 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) {}
* };
*/
class Solution {
public:
vector rightSideView(TreeNode* root) {
queue que;
vector result;
if (root == NULL) return result;
que.push(root);
while (!que.empty()){
int size = que.size();
vector vec;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
reverse(vec.begin(),vec.end());
result.push_back(vec[0]);
}
return result;
}
};
要层次遍历输出二叉树的最右侧节点,将每层收集到的节点数据vec容器的最右侧数据记录即可,由于每层节点个数不同,若将每层节点数据进行反转,则只需要记录容器的第一个数据即可,易于实现。
题目链接https://leetcode.cn/problems/average-of-levels-in-binary-tree/
/**
* 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) {}
* };
*/
class Solution {
public:
vector averageOfLevels(TreeNode* root) {
queue que;
vector result;
double ave = 0;
if (root == NULL) return result;
que.push(root);
while (!que.empty()){
int size = que.size();
int count = 0;
double sum = 0;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
sum += node->val;
count++;
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
ave = sum / count;
result.push_back(ave);
}
return result;
}
};
本题也很容易实现,只要将每层的节点数据进行求和循环结束后除以本层节点数即可得到平均值,然后存入结果容器中。
/*
// Definition for a Node.
class Node {
public:
int val;
vector children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector> levelOrder(Node* root) {
queue que;
vector> result;
if (root == NULL) return result;
que.push(root);
while (!que.empty()){
int size = que.size();
vector vec;
for (int i = 0; i < size; i++){
Node* node = que.front();
que.pop();
vec.push_back(node->val);
for (int i = 0; i < node->children.size(); i++){
if (node->children[i]) que.push(node->children[i]);
}
}
result.push_back(vec);
}
return result;
}
};
本题与前面几题有些略微差别,主要是每个节点可能有N个孩子,在进行遍历时对每个孩子都要进行循环遍历。
题目链接https://leetcode.cn/problems/find-largest-value-in-each-tree-row/
/**
* 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) {}
* };
*/
class Solution {
public:
vector largestValues(TreeNode* root) {
queue que;
vector result;
if (root == NULL) return result;
que.push(root);
while (!que.empty()){
int size = que.size();
int max = INT_MIN;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
max = (max < node->val ? node-> val : max);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(max);
}
return result;
}
};
难度不大,在层序遍历循环中进行最大值的判断和更新,最后遍历结束后result容器接收每层的最大值。
题目链接https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/description/
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue que;
if (root != NULL) que.push(root);;
while (!que.empty()){
int size = que.size();
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++){
if (i == 0){
nodePre = que.front();
que.pop();
node = nodePre;
}else{
node = que.front();
que.pop();
nodePre->next = node;
nodePre = nodePre->next;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL;
}
return root;
}
};
相比前几题多了些细节的考虑,要对首层做单独处理。在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点。
题目链接https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue que;
if (root != NULL) que.push(root);
while (!que.empty()){
int size = que.size();
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++){
if (i == 0){
nodePre = que.front();
que.pop();
node = nodePre;
}else{
node = que.front();
que.pop();
nodePre->next = node;
nodePre = nodePre->next;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL;
}
return root;
}
};
和前一题相同。
题目链接https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/
/**
* 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) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
queue que;
int count = 0;
if (root != NULL) que.push(root);
while (!que.empty()){
int size = que.size();
vector vec;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
count++;
}
return count;
}
};
相比下一题最小深度,最大深度的实现较为简便,因为二叉树的最大深度必定和二叉树的层数相同。
题目链接https://leetcode.cn/problems/minimum-depth-of-binary-tree/submissions/492258512/
/**
* 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) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
queue que;
int count = 0;
if (root != NULL) que.push(root);
while (!que.empty()){
int size = que.size();
count++;
for (int i = 0; i < size; i++){
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
if (!node->left && !node->right) return count;
}
}
return count;
}
};
只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点。
题目链接
文章链接
要翻转一棵二叉树,只要将左右子树每个节点的左右孩子进行互换即可实现。
/**
* 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) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
swap(root->left, root->right); //中
invertTree(root->left); //左
invertTree(root->right); //右
return root;
}
};
/**
* 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) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
invertTree(root->left); //左
invertTree(root->right); //右
swap(root->left, root->right); //中
return root;
}
};
/**
* 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) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack st;
if (root == NULL) return root;
st.push(root);
while (!st.empty()){
TreeNode* node = st.top();
if (node != NULL){
st.pop();
if (node->right) st.push(node->right);
if (node->left) st.push(node->left);
st.push(node);
st.push(NULL);
}else{
st.pop();
node = st.top();
st.pop();
swap(node->left, node->right);
}
}
return root;
}
};
/**
* 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) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack st;
if (root == NULL) return root;
st.push(root);
while (!st.empty()){
TreeNode* node = st.top();
if (node != NULL){
st.pop();
if (node->right) st.push(node->right);
if (node->left) st.push(node->left);
st.push(node);
st.push(NULL);
}else{
st.pop();
node = st.top();
st.pop();
swap(node->left, node->right);
}
}
return root;
}
};
层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍。
题目链接
文章链接
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的。其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。
比较的是两个子树的里侧和外侧的元素是否相等。
/**
* 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) {}
* };
*/
class Solution {
public:
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;
//进入递归
bool outside = compare(left->left, right->right);
bool inside = compare(left->right, right->left);
bool result = outside && inside;
return result;
}
bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
return compare(root->left, root->right);
}
};
本题使用递归只能采用后序法实现,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。
今天的体量有点大,主要练习二叉树层次遍历的使用,虽然十道层次遍历的练习大同小异,但是后面几道还是需要一些特别的变形和细节上的注意,还需要多多练习。二刷三刷再熟练掌握各种方法的应用。