Day 13 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度

47 阅读6分钟

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

第一反应:层序遍历

由于对称性需要考虑整个树,自己琢磨递归遍历无果,遂想到层序遍历,只需判断每层数组是否对称。若遇到空节点,用特殊值占位即可。

但初步想法是,如果当前节点左/右子节点非空,则入队;若为空,让一个val404(不在范围内即可),无左右子节点的树节点入队。这样的话,队列永远非空,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&&in;
        }
    }
};

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)

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

image.png

注意,根节点有右孩子,不是叶子节点

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,一直到回到给定的节点。