代码随想录第15天 | 层序遍历 、 226.翻转二叉树 (优先掌握递归) 、 101. 对称二叉树 (优先掌握递归)

一、前言

参考文献:代码随想录

  今天的题目比较多,但是应该都不会很难,我记得在我寒假刷的时候,刷了很久二叉树,发现有一段时间的i题目类型很类似(我大概一天一到两题),所以耽搁了比较久的时间,这次跟着代码随想录训练营,应该可以很快把二叉树给过掉。

二、层序遍历

1、思路:

层序遍历的模板都差不多,我总结了以下几点:

(1)层序遍历就好比广度搜索,利用的是队列的性质(先进先出)

(2)首先创建一个queue(队列)来存储遍历的值,首先存入的是root

(3)进入大循环,再把当前节点的值存入result中。

(4)把左右孩子放入队列中(至于是先放右孩子还是左孩子,取决于题目要求)

2、二叉树的层序遍历代码:

    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        queue<TreeNode*> que;
        if (root == NULL) return result;
        que.push(root);

        while (!que.empty()) 
        {
            int size = que.size();
            vector<int> temp;

            for (int i = 0; i < size; i++)
            {
                TreeNode* node = que.front();
                que.pop();
                temp.push_back(node->val);
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            // 把temp存到result中
            result.push_back(temp);
        }
        return result;
    }

3、二叉树的层序遍历 II代码:

这个题目就是从叶子节点开始遍历,与从根节点对比来说,只需要反转一下即可

代码如下:

    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> result;
        queue<TreeNode*> que;
        if (root == NULL) return result;

        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> temp;

            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                temp.push_back(node->val);
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            result.push_back(temp);
        }
        reverse(result.begin(), result.end());
        return result;
    }

4、二叉树的右视图代码:

右视图的解法与其类似,只需要把树每一层最后一个节点存起来就ok了

代码如下:

    vector<int> rightSideView(TreeNode* root) {
        vector<int> result;
        queue<TreeNode*> que;
        if (root == NULL) return result;

        que.push(root);

        while (!que.empty()) {
            int size = que.size();

            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                // 最后一个元素才添加
                if (i == size - 1) {
                    result.push_back(node->val);
                }
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        } 
        return result;
    }

5、二叉树的层平均值代码​​​​​​

这也是考察层序遍历,主要还是运用当前的框架,利用queue来实现每一层的遍历,求和以及求平均,代码如下:
 

    vector<double> averageOfLevels(TreeNode* root) {
        queue<TreeNode*> que;
        vector<double> result;
        if (root == NULL) return result;
        que.push(root);

        while (!que.empty()) {
            int size = que.size();
            double sum = 0;
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                sum += node->val;
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            // 传入平均值
            result.push_back(sum / size);
        }
        return result;
    }

6、N 叉树的层序遍历代码:

这个N叉树的遍历还是使用queue来左层序遍历,这里只是多了几个孩子节点。(我主要是不知道孩子节点应该如何去遍历) 查看了代码随想录之后,就明白了,孩子节点的遍历与数组差不多。

代码如下:

 vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> result;
        queue<Node*> que;
        if (root == NULL) return result;
        que.push(root);

        while (!que.empty()) {
            int size = que.size();
            vector<int> temp;

            for (int i = 0; i < size; i++) {
                Node* node = que.front();
                que.pop();
                temp.push_back(node->val);

                // 插入树的孩子节点
                for (int j = 0; j < node->children.size(); j++) {
                    que.push(node->children[j]);
                }
            }
            result.push_back(temp);
        }
        return result;
    }

7、在每个树行中找最大值代码:

这个题目也大差不差,主要差别就是多了一个判断大小的流程,其余都差不多。

代码如下:

  vector<int> largestValues(TreeNode* root) {
        vector<int> result;
        queue<TreeNode*> que;
        if (root == NULL) return result;
        que.push(root);

        while(!que.empty()) {
            int size = que.size();
            int max = INT_MIN;
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (node->val > max) {
                    max = node->val;
                } 
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            result.push_back(max);
        }
        return result;
    }

8、填充右节点代码:

其实都是大差不差,但是这里的关键就是需要设置两个指针,一个指针保存前一个节点,让这个节点能够指向后一个节点,再把最后的节点指向NULL就ok了。

代码如下:

    Node* connect(Node* root) {
        queue<Node*> que;
        if (root == NULL) return root;
        que.push(root);

        while (!que.empty()) {
            Node* nodeper; // 前一个节点
            Node* node;
            int size = que.size();
            for (int i = 0; i < size; i++) {
                if (i == 0) {
                    nodeper = que.front();
                    node = nodeper; // 这里必须设置,因为为头结点时,就需要通过这个节点访问
                    que.pop();
                } else {
                    node = que.front();
                    que.pop();
                    nodeper->next = node;
                    nodeper = node;
                }
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            nodeper->next = NULL; // 最后一个元素指向空
        }
        return root;
    }

9、填充右节点||代码:

这道题目与上一个题目相同,就是一模一样的题目,代码也一模一样,我就不列出来了。

10、二叉树的最大深度代码:

这道题目只要直接往下遍历,遍历一层,就统计加一就ok了。

代码如下:

    int maxDepth(TreeNode* root) {
        int depth = 0;
        queue<TreeNode*> que;
        if (root == NULL) return 0;
        que.push(root);

        while (!que.empty()) {
            int size = que.size();
            depth++;
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return depth;
    }

11、二叉树的最小深度代码:

与最大深度相比,多了一个出去的条件,两个左右孩子节点都为空时,就return

    int minDepth(TreeNode* root) {
        int depth = 0;
        queue<TreeNode*> que;
        if (root == NULL) return 0;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            depth++;
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
                if (node->left == NULL && node->right == NULL) { // 左右孩子都为空了,就说明到了最底层了,返回即可
                    return depth;
                }
            }
        }
        return depth;
    }

12、反转二叉树代码:

这个题目用的是递归的方法,比较抽象,所以我先使用的是迭代法。

我总结了以下几点

(1)可以使用栈或者队列,我这里使用的是队列。

(2)只需要按照之前的模板,但是不需要再遍历每一层的了,只需要交换,每一个左右节点就可以了。

(3)这里使用的是后序遍历。

代码如下:

 TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        queue<TreeNode*> que;
        que.push(root);

        while (!que.empty()) {
        TreeNode* node = que.front(); 
        que.pop();
        
        if (node->left) que.push(node->left);
        if (node->right) que.push(node->right);

        // 交换左右子节点
        TreeNode* temp = node->left;
        node->left = node->right;
        node->right = temp;
        }
        return root;
    }

递归法:

递归首先就是要确定:

(1)返回值和传入参数。

(2)终止条件

(3)处理过程

这里传入的参数是root指针,返回值是Treenode*类型的,终止条件就是root不额为空即可,中间过程看下列代码即可:

    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return NULL;
        swap(root->left, root->right);
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }

这里使用的是前序遍历,中序遍历不行,因为会反转两次,所以后序遍历也可以。

13、对称二叉树代码:

这个题目就是用递归解决的,这里需要确定终止条件(条件比较多),还有采用的比较抽象的遍历方式。

这里传入的参数是左子树和右子树,他需要分别比较内的和外侧,即:

right->right : left->left;

left->right : right->left;

这两进行比较

主要思路就是外侧和外侧的比较,内测和内侧的比较,比较完了就OK了。

代码如下:

private:
    bool comper(TreeNode* left,TreeNode* right) {
        if (left != NULL && right == NULL) return false;
        else if (right != NULL && left == NULL) return false;
        else if (right == NULL && left ==NULL) return true;
        // 值不相等
        else if (left->val != right->val) return false;
        // 开始内部实现,后序遍历
        return comper(left->left, right->right) && comper(right->left, left->right);
    }
public:
    bool isSymmetric(TreeNode* root) {
        return comper(root->left, root->right);
    }

这里的终止条件就是比较复杂:

(1)做指针为空,右指针不为空,返回 否

(2)左指针不为空,右指针为空, 返回 否

(3) 做指针为空, 右指针为空, 返回 真

(4)左指针和右指针的数值不相等, 返回 否

(5) 左指针和右指针数值相同,就继续往下去递归,判断左右节点的孩子节点是否对称。

今天的学习时间安慰两小时;

Leave a message:

How can a world be good in which money is the moving power,and self-interest the guiding star?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值