1. 层序遍历
二叉树的层序遍历需要需要用到队列,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
详细代码如下:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
//使用队列
queue<TreeNode*> q;
vector<vector<int>> res;
if(root==nullptr) return {}; //为空直接返回
q.push(root); //根节点入队
while(!q.empty())
{
int len = q.size(); //控制每层要输出的元素个数
vector<int> tmp;
for(int i=0;i<len;i++)
{
TreeNode* node = q.front();
q.pop();
tmp.push_back(node->val); //写入临时vector
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
res.push_back(tmp); //写入一层的元素
}
return res;
}
};
当然,也可以用递归法来实现层序遍历,学了代码随想录的思路总结如下:
1. 参数:相比前序中序后序遍历,需要多一个用来表示层数的参数,来把相应的元素添加到对应层;
2. 结束条件:当节点为空就return;
3. 每层的逻辑:首先如果层数等于res的尺寸,说明开始新的一层了,需要新增一个数组;
把当前节点的val值添加到对应的res[depth]里面去;接着递归其左右节点,需要注意,其左右节点的层数要加1。
递归法的代码:
class Solution {
public:
void layer(TreeNode* root, vector<vector<int>>&res, int depth)
{
if(root==nullptr) return;
if(res.size()==depth) res.push_back(vector<int>()); //添加新层
res[depth].push_back(root->val);
layer(root->left,res,depth+1);
layer(root->right,res,depth+1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
int depth=0;
layer(root,res,depth);
return res;
}
};
层序遍历理解后,可以一下拿下10道题,只需要改上述模板的两到三行!
学会二叉树的层序遍历,可以一口气打完以下十题:
- 102.二叉树的层序遍历(opens new window)
- 107.二叉树的层次遍历II(opens new window)
- 199.二叉树的右视图(opens new window)
- 637.二叉树的层平均值(opens new window)
- 429.N叉树的层序遍历(opens new window)
- 515.在每个树行中找最大值(opens new window)
- 116.填充每个节点的下一个右侧节点指针(opens new window)
- 117.填充每个节点的下一个右侧节点指针II(opens new window)
- 104.二叉树的最大深度(opens new window)
- 111.二叉树的最小深度
226.翻转二叉树
这道题的思路是前序遍历,每次处理的逻辑是交换左右节点,然后依次递归左右子树,详细代码如下:
class Solution {
public:
void invert(TreeNode* root)
{
if(root==nullptr) return;
swap(root->left,root->right);
invert(root->left);
invert(root->right);
}
TreeNode* invertTree(TreeNode* root) {
invert(root);
return root;
}
};
101. 对称二叉树
这道题目的结束条件比较多,需要仔细思考每种情况;使用后序遍历的思路来做即可。递归三部曲:
1. 确定递归函数的参数和返回值
因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。
返回值自然是bool类型。
2. 确定终止条件
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。
节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
- 左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:
- 左右都不为空,比较节点数值,不相同就return false
此时左右节点不为空,且数值也不相同的情况我们也处理了。
3. 处理每层逻辑
对比两个外侧和内侧的左右节点是否相等,然后返回左右节点的逻辑与结果(这里体现了后序)。
详细代码如下:
class Solution {
public:
bool isEqual(TreeNode* left, TreeNode* right)
{
//后序遍历
//结束条件
if(left==nullptr&&right!=nullptr) return false;
else if(left!=nullptr&&right==nullptr) return false;
else if(left==right&&left==nullptr) return true;
else if(left->val!=right->val) return false;
bool l = isEqual(left->left,right->right);
bool r = isEqual(left->right, right->left);
return l&&r;
}
bool isSymmetric(TreeNode* root) {
return isEqual(root->left,root->right);
}
};