层序遍历
层序遍历是将二叉树从上到下,从左到右一层一层去遍历。可借助队列来实现,队列先进先出,每次可将队列头节点出队列时,让其孩子进入队列。
需要注意的是,层序遍历返回的是有一定树结构的二维vector,第一维度是树的层高。第二维度保存的是该层内节点的值。因此,要先查看队列的长度,然后弹出该长度个节点。
class Solution{
public:
vector<vector<int>> levelOrder(TreeNode* root){
vector<vector<int>> result;
if(root == nullptr)return result;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size = que.size();//该层的节点数
vector<int> temp;//该层节点的值
while(size--){//不能--size
TreeNode* cur = que.front();
temp.push_back(cur->val);
if(cur->left!=nullptr)que.push(cur->left);//先左
if(cur->right!=nullptr)que.push(cur->right);//后右
}
//该层处理完后,保存结果
result.push_back(temp);
}
return result;
}
}
LC 102.二叉树的层序遍历
题目链接:LC 102.二叉树的层序遍历
思路:上面经典的层序遍历即可
代码:
/**
* 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<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root!=nullptr)que.push(root);
while(!que.empty()){
int size = que.size();//保存该层节点个数,提前保存防止pop和push后,队列大小发生改变
vector<int> temp;//保存每层结果
//弹出size个节点
while(size--){
TreeNode* cur = que.front();
que.pop();
temp.push_back(cur->val);
if(cur->left!=nullptr)que.push(cur->left);
if(cur->right!=nullptr)que.push(cur->right);
}
result.push_back(temp);
}
return result;
}
};
LC 107.二叉树的层次遍历II
题目链接:LC 107.二叉树的层次遍历II
思路:自低向上遍历,每层仍是从左到右,那直接从上到下遍历,然后再反转就可以了,或者每次遍历完一层,插入的时候插入到vector<vector>的前面。
代码:
/**
* 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<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root!=nullptr)que.push(root);
while(!que.empty()){
int size = que.size();
vector<int> temp;
while(size--){
TreeNode* cur = que.front();
que.pop();
temp.push_back(cur->val);
if(cur->left!=nullptr)que.push(cur->left);
if(cur->right!=nullptr)que.push(cur->right);
}
// result.emplace(result.begin(), temp);
// result.insert(result.begin(), temp);
result.push_back(temp);
}
// return result;
reverse(result.begin(),result.end());
return result;
}
};
LC 199.二叉树的右视图
题目链接:LC 199.二叉树的右视图
思路:如果不把这个题放在层次遍历中,很难想到用层次遍历,第一反应是深度遍历先遍历右边。但是万一没有右子树,只有左子树,怎么判断?
因此看到一层只有一个输出,或者输出和层有关系就要考虑层次遍历。
按照层次遍历的思路,需要对以下方面进行修改:
返回的是一维vector;
每层只需保存最后一个数。
代码:
/**
* 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<int> rightSideView(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root!=nullptr)que.push(root);
while(!que.empty()){
int size = que.size();
while(size--){
TreeNode* cur = que.front();
que.pop();
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
if(size==0)result.push_back(cur->val);
}
}
return result;
}
};
LC 637.二叉树的层平均值
题目链接:LC 637.二叉树的层平均值
思路:每层遍历完之后就计算平均值,然后保存。
代码:
/**
* 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<double> averageOfLevels(TreeNode* root) {
vector<double> result;
queue<TreeNode*> que;
if(root)que.push(root);
while(!que.empty()){
double size = que.size();
double sum = 0;
for(int i=0; i<size; i++){
TreeNode* cur = que.front();
que.pop();
sum+=cur->val;
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
}
result.push_back((double)sum/size);
}
return result;
}
};
LC 429.N叉树的层序遍历
题目链接: LC 429.N叉树的层序遍历
思路:和二叉树层序遍历的主要区别就是在pop出一个队列的节点后,需要将这个节点的孩子节点都放入队列中;而二叉树只需要放入左右两个孩子节点。
代码:
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> result;
queue<Node*> que;
if(root)que.push(root);
while(!que.empty()){
int size = que.size();//一层节点多少
vector<int> temp;//保存这一层的节点
while(size--){
Node* cur = que.front();
que.pop();
temp.push_back(cur->val);
//把节点cur的孩子都放入队列中
int child_size = cur->children.size();
for(int i=0; i<child_size; i++){
que.push(cur->children[i]);
}
}
result.push_back(temp);
}
return result;
}
};
LC 515.在每个树行中找最大值
题目链接:LC 515.在每个树行中找最大值
思路:遍历每一层的时候,若见到比这层已遍历的数大的值,就将该值保存为最大数。
代码:
/**
* 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<int> largestValues(TreeNode* root) {
vector<int> result;
queue<TreeNode*> que;
if(root)que.push(root);
while(!que.empty()){
int size = que.size();
int max = INT_MIN;
while(size--){
TreeNode* cur = que.front();
que.pop();
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
if(max<cur->val)max = cur->val;
}
result.push_back(max);
}
return result;
}
};
LC 116.填充每个节点的下一个右侧节点指针
题目链接:LC 116.填充每个节点的下一个右侧节点指针
思路:每个节点多了一个next指针,next指针指向该节点该层的右侧节点,用层次遍历,每次弹出一个元素后,让弹出元素指向队列头元素。
代码:
/*
// 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<Node*> que;
if(root)que.push(root);
while(!que.empty()){
int size = que.size();
while(size--){//除了最后一个指针指向nullptr,其它的都指向下一个节点
Node* cur = que.front();
que.pop();
if(size==0) cur->next = nullptr;
else{cur->next = que.front();}
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
}
}
return root;
}
};
LC 117.填充每个节点的下一个右侧节点指针II
题目链接:LC 117.填充每个节点的下一个右侧节点指针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<Node*> que;
if(root)que.push(root);
while(!que.empty()){
int size = que.size();
while(size--){//除了最后一个指针指向nullptr,其它的都指向下一个节点
Node* cur = que.front();
que.pop();
if(size==0) cur->next = nullptr;
else{cur->next = que.front();}
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
}
}
return root;
}
};
LC 104.二叉树的最大深度
题目链接:LC 104.二叉树的最大深度
思路:这个题看着虽然像深度遍历的思路,但是深度遍历不确定啥时候是最深深度,只能每次到叶子节点保存并比较之前的深度,而且当从叶子节点回溯时,也容易出错。不如直接层次遍历,最深的层数就是二叉树的最大深度。
代码:
/**
* 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) {
int result = 0;
queue<TreeNode*> que;
if(root)que.push(root);
while(!que.empty()){
int size = que.size();
while(size--){
TreeNode* cur = que.front();
que.pop();
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
}
result++;
}
return result;
}
};
LC 111.二叉树的最小深度
题目链接:LC 111.二叉树的最小深度
思路:有关二叉树深度的题,首先要想到层次遍历,因为层次遍历不用考虑,节点回溯的问题,也不用判断节点是否是叶子节点。只用层次遍历,当遇到节点的左右子树都为空时就返回。
代码:
/**
* 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) {
int result;
queue<TreeNode*> que;
if(root){que.push(root);result = 1;}
else{result = 0;}
while(!que.empty()){
int size = que.size();
while(size--){
TreeNode* cur = que.front();
que.pop();
if(cur->left==nullptr && cur->right==nullptr)return result;
if(cur->left)que.push(cur->left);
if(cur->right)que.push(cur->right);
}
result++;
}
return result;
}
};
LC 226.翻转二叉树
题目链接:LC 226.翻转二叉树
思路:直接用swap将二叉树的每个节点的左右子树反转。递归思路:前序遍历,每次将节点的左右子树交换地址,当节点为nullptr时,就返回。
代码:
/**
* 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:
//深度遍历-先序遍历-递归
//1 确定传入参数和返回参数类型
// TreeNode* invertTree(TreeNode* root) {
// //2 确定返回条件(终止条件)
// if(root == nullptr)return root;
// //3 单层递归逻辑
// //先反转,再到左右子树(先序遍历)
// swap(root->right, root->left);
// invertTree(root->right);
// invertTree(root->left);
// return(root);
// }
void reverseTree(TreeNode* cur){
if(cur)swap(cur->right, cur->left);
else return;
reverseTree(cur->left);
reverseTree(cur->right);
}
TreeNode* invertTree(TreeNode* root) {
if(root)reverseTree(root);
return root;
}
};
**递归中序遍历不合适,因为先处理左子树,然后处理中间节点(回退的父节点),然后是右子树,但是处理中间节点的时候将左右子树翻转了,最后处理右子树其实是重复的。**解决办法是遍历完中间节点后继续遍历左子树,但是不优雅,不容易理解。
LC 101. 对称二叉树
题目链接: LC 101. 对称二叉树
思路:判断二叉树是否是镜像对称的。递归思路:从根节点开始,判断根节点的左右两个子节点是否相同。若不同,则直接返回false,若都为空节点也直接返回true。若相同,则继续递归,判断左节点的左子节点和右节点的右子节点(外侧)是否相同,左节点的右子节点和右节点的左子节点(内侧)是否相同。若都相同则返回true,若有一个不同则是false。递归返回到的是上一层。
代码:
/**
* 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:
//判断left和right子树是否对称
//首先判断left和right是否相等。
//若相等就判断两节点的子节点
//若不相等就返回false
//若都为空节点则返回true
bool compare(TreeNode* left, TreeNode* right){
//先判断left和right
if(left==nullptr && right==nullptr)return true;//都为空
else if(left==nullptr && right!=nullptr)return false;//一个为空一个不为空
else if(left!=nullptr && right==nullptr)return false;
else if(left->val!=right->val)return false;//都不为空,但值不一样
//排除完之后,剩下的情况就是,节点不为空,且节点值一样
//那么就可以继续递归。判断:内侧相同,外侧相同
bool in = compare(left->right, right->left);
bool out = compare(left->left, right->right);
bool result = in&&out;
return result;
}
bool isSymmetric(TreeNode* root) {
if(root == nullptr) return true;
bool result = compare(root->left, root->right);
return result;
}
};