Leetcode数据结构入门第十一天(树的应用(1))
之前的文章:树的前序,中序,后序遍历
102. 二叉树的层序遍历
题目描述
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
样例
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
思路
树的层序遍历就是一层一层从左往右访问每个节点,因为队列是FIFO先进先出原则,所以可以用来存储每一层节点,具体实现:因为根节点为第一层,所以先把根节点压入队列,开始遍历,每一层节点数就是队列的长度len,循环len次,每次把队首元素值压入临时一元数组inner中,并出队,再把当前队首元素的左右孩子节点压入队列中(放在后面,不影响该层节点)。循环结束,把当层节点的内层结果压入总结果中,然后继续下一层的循环,直到队列为空,遍历结束。
参考代码
/**
* 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>> res;
//如果根节点为空直接返回
if(root==NULL) return res;
//用队列存储当前节点的下一层子节点
queue<TreeNode*> que;
//初始化:把根节点压入队列
que.push(root);
//当队列非空时,将当前队列值存入同一层结果中,并出队,同时让下一层节点入队
while(!que.empty())
{
int len=que.size();//当前队列长度
//vector<int> inner(len);//内层结果:一开始为空,注意这样新建节点,push_back是在所有节点后新建节点,所以这样会多出几个节点值为0。
vector<int> inner;
//i没有实际意义,只是循环len次
for(int i=0;i<len;i++)
{
//获得队头元素,并出队
TreeNode* node=que.front();
que.pop();
//压入队列
inner.push_back(node->val);
//当前节点的下层子结点顺便压入队列
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
//循环结束,把当层节点的内层结果压入总结果中
res.push_back(inner);
}
return res;
}
};
104. 二叉树的最大深度
题目描述
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
样例
输入:[3,9,20,null,null,15,7],
输出:3
思路一
求最大深度,实际上就是判断该树有多少层,所以基本上套用层序遍历(广度优先搜索)的方法即可,因为这里只需要判断层数,所以不需要层序遍历的结果,可以直接化简掉,只需要在每层内层循环后,深度++,最后返回深度即可。
参考代码
/**
* 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) {
//广度优先搜索:即层序遍历
if(root==NULL) return 0;
int max=0;
//队列存储每一层节点值
queue<TreeNode*> que;
que.push(root);
while(!que.empty())
{
int len=que.size();//表示这一层的节点数
//遍历len次,把下一层节点从左往右压入队列
for(int i=0;i<len;i++)
{
TreeNode* node=que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
//每进行一次内层for循环,层数加1
max++;
}
return max;
}
};
思路二
深度优先搜索(递归法):
如果知道左子树的最大深度和右子树的最大深度,那么最大深度=两者中的最大值+1
不断递归,左子树和右子树的最大深度又可以按照同样方式求出来,而递归终点为根节点为空。
参考代码
/**
* 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) {
//深度优先搜索:递归法
//递归终点
if(root==NULL) return 0;
//递归参数:只需要根节点即可,
//递归返回值:还是这个最大深度
return 1+max(maxDepth(root->left),maxDepth(root->right));
}
};
101. 对称二叉树
题目描述
给你一个二叉树的根节点 root , 检查它是否轴对称。
样例一
输入:root = [1,2,2,3,4,4,3]
输出:true
样例二
输入:root = [1,2,2,null,3,null,3]
输出:false
思路一
递归法:判断二叉树对称,比较的是根节点的左右子树是否相互翻转,实际上就是判断两子树的外侧子节点和内侧子节点是否相等:
(外侧:左子树的左子节点与右子树的右子节点
内侧:左子树的右子节点与右子树的左子节点)
递归三步走:
- 确定递归函数的参数,返回值
比较的是两个树:左子树,右子树,所以参数为两个树节点,返回值为bool类型 - 确定递归终点
两个树节点数值比较,有三种情况,递归终止:
(1)左右子树都为空,说明是对称,返回true
(2)左右子树只有一个为空,不对称,返回false
(3)左右子树都不为空,但是数值不相等,也是不对称,返回false - 处理单层递归逻辑
不满足递归终点,说明左右树节点都不为空,且数值相等:可以比较当前左右子树节点的外侧子节点和内侧子节点是否相等,如果左右都对称即返回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:
//递归函数:
//参数:比较的是两个树:左子树,右子树
bool compare(TreeNode* left,TreeNode* right)
{
//递归终点:
//左右子树都为空,就是对称的
if(left==NULL&&right==NULL) return true;
//有一个为空,一个不为空,不对称
else if(left==NULL&&right!=NULL||left!=NULL&&right==NULL) return false;
//左节点的值不等于右节点值,也是不对称
else if(left->val!=right->val) return false;
//递归单层逻辑:处理左节点值=右节点值,判断他们子树怎么样
//外层:左节点的左,右节点的右
bool out=compare(left->left,right->right);
//内层:左节点的右,右节点的左
bool in=compare(left->right,right->left);
//只有内层和外层都相等才是对称的
return out&∈
}
bool isSymmetric(TreeNode* root) {
if(root==NULL) return true;
else return compare(root->left,root->right);
}
};
思路二
迭代法(不是层序遍历):这里使用队列,其实只是用做一个容器,按照顺序把左右两个子树用于比较的节点存储进去,然后成对取出来比较。
具体实现:首先把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 isSymmetric(TreeNode* root) {
if(root==NULL) return true;
queue<TreeNode*> que;
//初始:先让左右子树的根节点入队
que.push(root->left);
que.push(root->right);
//判断两子树是否对称
while(!que.empty())
{
//取出当前的左右子树根节点,用于比较
TreeNode* left=que.front();
que.pop();
TreeNode* right=que.front();
que.pop();
//判断:
//左右子树都为空
if(left==NULL&&right==NULL) continue;
//只有一个为空:不对称,直接返回了
else if(left==NULL||right==NULL) return false;
//左右子树节点数值不等
else if(left->val!=right->val) return false;
//判断结束后:把当前左右子树的外侧节点和内侧节点压入队列,用于下一层比较
//外侧节点
que.push(left->left);
que.push(right->right);
//内侧节点
que.push(left->right);
que.push(right->left);
}
return true;
}
};