226. 翻转二叉树 - 力扣(LeetCode)
给你一棵二叉树的根节点
root,翻转这棵二叉树,并返回其根节点。
遍历一次二叉树即可,并在遍历的函数中加入操作swap(root->left,root->right)
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
traverse(root);
return root;
}
};
后序、前序
void traverse(TreeNode* root){
if(root==nullptr) return;
//swap(root->left,root->right);//写在这是前序,在访问完左右子节点之前交换
traverse(root->left);
traverse(root->right);
//swap(root->left,root->right);//写在这是后序,在访问完左右子节点之后交换
}
中序
void traverse(TreeNode* root){
if(root==nullptr) return;
traverse(root->left); //遍历完左子树
swap(root->left,root->right); //交换左右子树
traverse(root->left); //尚未遍历的右子树在交换后是左子树,因此还是遍历左子树
}
101. 对称二叉树 - 力扣(LeetCode)
给你一个二叉树的根节点
root, 检查它是否轴对称。 提示:
- 树中节点数目在范围
[1, 1000]内-100 <= Node.val <= 100
第一反应:层序遍历
由于对称性需要考虑整个树,自己琢磨递归遍历无果,遂想到层序遍历,只需判断每层数组是否对称。若遇到空节点,用特殊值占位即可。
但初步想法是,如果当前节点左/右子节点非空,则入队;若为空,让一个val为404(不在范围内即可),无左右子节点的树节点入队。这样的话,队列永远非空,while循环的条件要调整,或者在循环体内加一个判断,数组是否全为404,若是说明全是空,应该结束循环。但逻辑可以改进。
不考虑当前节点的左右子节点,而是本身。
- 若当前节点
非空,把val记入数组,把左右子节点加入队列。 - 若当前节点为
空,把404记入数组标记,当然,也不用处理子节点,因为没有
也就是说,如果一个节点为空,只会往数组中写入404标记,它没有子节点再进入队列,也无法走到下一层;
如果一个节点非空,会往数组写入自己的val,还会把子节点写入数组,即使是空的子节点也没关系,因为在处理下一层遇到该空子节点时,只会把404记入数组。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
queue<TreeNode*> q;
if(root==nullptr) return true;
q.push(root);
while(!q.empty()){
int size = q.size();
vector<int> level;
for(int i = 0;i<size;i++){
if(q.front()){//队首元素非空指针
level.push_back(q.front()->val);//数组push该节点val
q.push(q.front()->left); //加入左子节点
q.push(q.front()->right); //加入右子节点
}
else level.push_back(404);//队首元素为空,数组push404来占位
q.pop();//删除队首元素
}
//for循环结束,处理完二叉树完整的一行,获得该行的数组
if(isSymmetricarray(level)==0) return false;
}
return true;
}
//判断数组是否对称
bool isSymmetricarray(vector<int> nums){
int left =0;
int right = nums.size()-1;
while(left<right){
if(nums[left]==nums[right]){
left++;
right--;
}
else return false;
}
return true;
}
};
递归
相当于一棵树上有两个指针,同时对称移动,比较是否为空,值是否相同
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return cmp(root->left,root->right);
}
bool cmp(TreeNode* left,TreeNode* right){
if(left==nullptr&&right!=nullptr) return false;
else if(left!=nullptr&&right==nullptr) return false;
//👆上面两个分支说明左右不同深度,肯定不对称
else if(left==nullptr&&right==nullptr) return true;//均为空也是对称的
//👆如果不进这个分支,说明均非空
else if(left->val!=right->val) return false;
else{
bool out = cmp(left->left,right->right);//传递到下层的外侧
bool in = cmp(left->right,right->left);//传递到下层的内侧
return out&∈
}
}
};
104. 二叉树的最大深度 - 力扣(LeetCode)
给定一个二叉树
root,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
节点深度:根节点到该节点路径上的节点数
节点高度:该节点到叶子节点路径上的节点数
最大深度,就是根节点的高度
当传入的节点为nullptr时,该节点为叶子节点的子节点,此时的高度为0。该节点的父节点为叶子节点,高度为1。只有碰到叶子节点,高度才真正有一个值,接下来每完成一层嵌套高度就加1。分别对应下面两处return。
class Solution {
public:
int maxDepth(TreeNode* root) {
return get(root);
}
//后序遍历求高度
int get(TreeNode* node){ //叶子节点高度为1,类似音程
if(node == nullptr) return 0;//空指针(叶子节点的儿子)的高度为0
int LMAX = get(node->left);
int RMAX = get(node->right);
return 1+max(LMAX,RMAX);//结束一层嵌套,高度加1
}
};
559. N 叉树的最大深度 - 力扣(LeetCode)
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
思路一样,不过多叉树的子节点是一个数组,且可能不满,对于三叉树,无法直接用[0][1][2]的下标去访问,有可能会越界,应该根据node->children.size()进行循环。
class Solution {
public:
int maxDepth(Node* root) {
return get(root);
}
int get(Node* node){
int high = 0;
if(node==nullptr) return 0;
for(int i = 0;i<node->children.size();i++){
int k = get(node->children[i]);
high=max(high,k);
}
return high+1;
}
};
111. 二叉树的最小深度 - 力扣(LeetCode)
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
注意,根节点有右孩子,不是叶子节点
class Solution {
public:
int minDepth(TreeNode* root) {
return get(root);
}
int get(TreeNode* node){
if(node==nullptr) return 0;
else if(!node->left&&!node->right)return 1;//左右均为空,该点是叶子节点
int Lmin = get(node->left);
int Rmin = get(node->right);
if(!node->left) return 1+Rmin; //如果没有左子树,最小深度是右子树加1
else if(!node->right) return 1+Lmin; //如果没有右子树,最小深度是左子树加1
else return 1+min(Lmin,Rmin);
}
};
深度、高度
- 深度 :距离根节点
- 高度 :距离叶子节点
前序求的是深度,后序求的是高度
后序遍历:从给定的节点出发,通过一层层嵌套向下延伸到叶子节点,叶子节点的高度为1,遍历完叶子节点的左右节点后结束一层嵌套,回到上一层,高度加1,一直到回到给定的节点。