Bootstrap

代码随想录算法训练营第十二天| 二叉树 层序遍历 226.翻转二叉树 101. 对称二叉树

层序遍历

只使用二叉树无法完成层序遍历,需要借助其他数据结构,使用的是队列。首先,插入根结点,然后设置循环条件(一般来说,需要借助队列/堆栈实现的循环,循环条件都会包含这些数据结构)。记录遍历完每层后结点的数量(可以设置size为容器大小值,表示当前层结点的数量),size用于防止队列上本层结点与下一层结点混肴。

102. 二叉树的层序遍历

出现错误:
1.直接使用if(!root)而不是if(root!=NULL)

2.对于队列来说,获取队列头元素是front函数,而不是top

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        vector<vector<int>> res;
        if(root!=NULL) que.push(root);
        while(!que.empty()){
            vector<int> vec;
            int size=que.size();
            while(size--){
                TreeNode* node=que.front();
                que.pop();
                vec.push_back(node->val);
                if(node->left)que.push(node->left);
                if(node->right)que.push(node->right);
            }
            res.push_back(vec);
        }
        return res;
    }
};

107. 二叉树的层序遍历 II

对比前面只需要添加一个翻转函数

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        queue<TreeNode*> que;
        vector<vector<int>> res;
        if(root!=NULL) que.push(root);
        while(!que.empty()){
            int size=que.size();
            vector<int> vec;
            while(size--){
                TreeNode* node=que.front();
                que.pop();
                vec.push_back(node->val);
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
            res.push_back(vec);
        }
        reverse(res.begin(),res.end());
        return res;
    }
};

226. 翻转二叉树

层序遍历法

本题之前使用层序遍历的方式,还是使用size记录当前层的结点数量,然后当队列加入下一层子结点后,将队列弹出的node的左右子节点交换,用来实现结点交换

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        queue<TreeNode*> que;
        if(root)que.push(root);
        while(!que.empty()){
            int size=que.size();
            for(int i=0;i<size;i++){
                TreeNode* node=que.front();
                TreeNode* tmp;
                que.pop();
                if(node->right)que.push(node->right);
                if(node->left)que.push(node->left);
                tmp=node->left;
                node->left=node->right;
                node->right=tmp;
            }
        }
        return root;
    }
};

递归法

 还有一种使用递归的方法进行翻转,需要掌握递归的方法,首先确定递归函数的参数和返回值,由题目可得参数类型以及返回值,然后确定循环终止条件,当此时结点为空时跳出当前层,然后再根据递归逻辑确立。本题可以使用前序遍历和后序遍历,直接使用中序遍历时会出错,因为中序遍历会照成结点翻转两次。

在本题中,通过打印结果可以看到递归遍历的结点,首先将左右对换后,再遍历对换后的左结点,然后再右结点所以输出出来结果是反着的。

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)return root;
        cout<<root->val<<" ";
        swap(root->left,root->right);
        invertTree(root->left);
        invertTree(root->right);

        return root;
    }
};

 101. 对称二叉树

层序遍历法

使用层序遍历可以完成,在层序遍历中,第一次不需要将头结点放入队列中,而是可以将其子节点放入队列中,然后根据队列上面左右节点判断其是否存在,是否相同,最后再将子节点中的子结点按照对称的顺序放入队列中即可。

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        queue<TreeNode*> que;
        if(root==NULL)return true;
        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&&!right)continue;
            if ((!left || !right || (left->val != right->val))) {
                return false;//要分析好left和right的情况,因为不可能同时为0,所以只要有一个为0,就会返回false
            }
            que.push(left->left);
            que.push(right->right);
            que.push(left->right);
            que.push(right->left);
        }
        return true;
    }
};

递归法

确定递归顺序。本题使用后序,使用后序遍历的情况:收集孩子信息向上一结点返回

1.首先确定函数参数类型以及返回值:因为要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树(因此确定函数参数类型为bool),所以要比较的是两个树,参数自然也是左子树节点和右子树节点。

2.判断终止条件:

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true
  • 左右不为空,但是值不同,return false

剩下的就是左右节点都不为空,且数值相同的情况,然后以此进行判断

3.确定单层递归的逻辑

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。
class Solution {
public:
    bool compare(TreeNode* left,TreeNode* right){
        if(!left&&right)return false;
        else if(left&&!right)return false;
        else if(!left&&!right)return true;
        else if(left->val!=right->val)return false;
        bool outside=compare(left->left,right->right);//左
        bool inside=compare(left->right,right->left);//右
        return outside&&inside;//中
    }
    bool isSymmetric(TreeNode* root) {
        if(!root)return true;
        return compare(root->left,root->right);
    }
};

;