二叉树的层序遍历

层序遍历相比较迭代和递归来说,简单很多。使用额外容器queue来存放结点,将一层的元素存入到队列中,再按顺序输出。因为队列是先进先出,所以按照左右的顺序正常压入就行。代码如下:

vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;vector<vector<int>> ans;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size(); //que的size表示这次需要处理几个结点vector<int> vec;while(size--){TreeNode* cur = que.front(); //当前需要处理的结点que.pop();vec.push_back(cur->val);//弹出后需要将其左右孩子压入队列,在下一次循环中遍历if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}ans.push_back(vec);vec.clear();}return ans;}

因为这里输出的是二维数组,所以在while循环中需要初始化一个储存当前层的元素。

LeetCode 637. 二叉树的层平均值

vector<double> averageOfLevels(TreeNode* root) {vector<double> ans;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();double sum = 0;for(int i = 0; i < size ; i++){TreeNode* cur = que.front();sum += cur->val;que.pop();if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}ans.push_back(sum / size);}return ans;}

本题需要注意的就是sum需要是double类型。另外因为需要求平均值,所以不能使用while(size--)循环,改为for(int i = 0; i < size ; i++)

LeetCode 429. N 叉树的层序遍历

这题其实没什么东西,很简单。只不过是在处理当前节点的子节点时,从左右孩子变成了遍历一个结点数组。

vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> ans;queue<Node*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();vector<int> vec;while(size--){Node* cur = que.front();vec.push_back(cur->val);que.pop();for(auto it = cur->children.begin(); it != cur->children.end(); it++){que.push(*it);}}ans.push_back(vec);}return ans;}

LeetCode 515. 在每个树行中找最大值

之前做过类似找最大最小值的题目,这里令对比对象初始化为INT_MIN

vector<int> largestValues(TreeNode* root) {vector<int> ans;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();int temp = INT_MIN;while(size--){TreeNode* node = que.front();temp = node->val > temp ? node->val : temp;que.pop();if(node->left) que.push(node->left);if(node->right) que.push(node->right);}ans.push_back(temp);}return ans;}

LeetCode 116. 填充每个节点的下一个右侧节点指针

本题就是在遍历时加一个判断,如果为本层最后一个结点,使其指向NULL即可。

Node* connect(Node* root) {queue<Node*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();while(size--){Node* cur = que.front();que.pop();if(size != 0){cur->next = que.front();}else{cur->next = NULL;}if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return root;}

LeetCode 104. 二叉树的最大深度

这里要知道二叉树深度的概念,以及高度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
二叉树的高度是表示当前结点所在的位置。比如二叉树最下方的叶子结点的高度为1,根节点的高度与深度相同。
采用层序遍历,在一层结束后,depth++即可。

int maxDepth(TreeNode* root) {int ans = 0;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();while(size--){TreeNode* cur = que.front();que.pop();if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}ans++;}return ans;}

111. 二叉树的最小深度

当左右孩子都为空的时候,才说明遍历到最低点了,如果其中一个孩子为空则不是最低点。所以当找到左右孩子都为空的结点时,直接返回结果即可。

int minDepth(TreeNode* root) {int min = 0;queue<TreeNode*> que;if(root != NULL) que.push(root);while(!que.empty()){int size = que.size();min++;while(size--){TreeNode* cur = que.front();que.pop();//找到即返回if(cur->left == NULL && cur->right == NULL) return min;if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return min;}

LeetCode 226. 翻转二叉树

本题也是有很多解法,递归迭代都可以实现。

  • 递归
    递归上来还是三部曲:

    1. 输入就是当前需要反转的结点,输出就是反转过后的结点。
    2. 终止条件是空结点时,结束本层递归
    3. 递归函数体就是反转左右结点

    代码如下:

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

    后序递归的话只需要把反转逻辑放在最后即可。
    如果是中序遍历,会将一个结点反转两次,所以不推荐中序,中序需要把代码写成这样:

        invertTree(root->left);         // 左swap(root->left, root->right);  // 中invertTree(root->left);        // 右
    

    我需要反转的右结点实际上是经过反转后的左节点,所以反转两次left。

  • 迭代
    迭代其实也很简单,在遍历的过程中添加一个swap完成反转,代码如下:

    TreeNode* invertTree(TreeNode* root) {if(root == NULL) return root;stack<TreeNode*> st;st.push(root);while(!st.empty()){TreeNode* cur = st.top();st.pop();swap(cur->left,cur->right);  //中if(cur->right) st.push(cur->right); //右if(cur->left) st.push(cur->left); //左}return root;}
    

    这里只给出前序迭代的代码,后序类似。

    迭代的统一写法(前序):

    TreeNode* invertTree(TreeNode* root) {stack<TreeNode*> st;if(root == NULL) return root;st.push(root);while(!st.empty()){TreeNode* cur = st.top();if(cur != NULL){st.pop();if(cur->right) st.push(cur->right);if(cur->left) st.push(cur->left);st.push(cur);st.push(NULL);}else{st.pop();cur = st.top();swap(cur->left, cur->right);st.pop();}}return root;
    }
    

    还是一样,在处理中间结点的时候swap一下。

  • 层序
    最后是层序,层序这题也可以做,相同的思路,一样的味道。
    代码如下:

    TreeNode* invertTree(TreeNode* root) {queue<TreeNode*> que;if(root == NULL) return root;que.push(root);while(!que.empty()){int size = que.size();while(size--){TreeNode* cur = que.front();que.pop();swap(cur->left,cur->right);if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return root;
    }
    

LeetCode 101. 对称二叉树

这题leetcode上给出的是简单难度,实际上思路和代码复杂度上怎么说也得是个中等难度。
首先需要搞清楚几种情况:

  • 左节点为空,右节点不为空,不对称
  • 左不为空,右为空,不对称
  • 左右都为空,对称
  • 左右都不为空且值不等,不对称
  • 左右都不为空且值相等,对称

然后要清楚对比的是二叉树两侧的结点,分为内侧和外侧。下面给出卡哥的图:

这样看比较清晰。
最后看一颗二叉树是否是对称二叉树,实际上是对比这颗树的左右子树,也就是对两棵子树同时进行遍历。
接下来就是考虑使用的遍历方式和遍历顺序,首先是递归遍历。

  • 递归
    递归的三要素:

    1. 输入输出:输入应该是两侧的两个结点left和right进行对比,所以输入是两个参数,输出即是否对称,为bool
    2. 终止条件:不对称即false,直接退出递归
    3. 递归函数体

    递归代码如下:

    bool compare(TreeNode* left , TreeNode* right){if(left != NULL && right == NULL) return false;else if(left == NULL && right != NULL) return false;else if(left == NULL && right == NULL) return true;else if(left->val != right->val) return false;//else return compare(left->left, right->right) && compare(left->right, right->left);bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)return isSame;
    }
    

    先把外侧的结点处理完成,再处理内侧结点,也就是代码中的outsideinsideleft->left就是左子树继续往外走,right->right就是右子树继续往外走。最后返回值必须两者都是true才说明是对称。
    其次注意if和else if语句中的顺序,首先需要把有可能出现空结点的情况讨论完,再去讨论不是空结点的情况,否则会出现访问空结点的错误。

  • 迭代
    迭代遍历首先还是要模拟一下入栈和出栈的过程,只有把过程搞明白了,才能写出正确的代码。直接看代码以及注释:

    bool isSymmetric(TreeNode* root) {queue<TreeNode*> que;//因为是同时遍历左右子树,所以要先把根节点的左右孩子压入que.push(root->left);que.push(root->right);while(!que.empty()){//取出结点进行对比。先压入再取出处理也是迭代中必须的手法TreeNode* l = que.front();que.pop();TreeNode* r = que.front();que.pop();if(l == NULL && r == NULL) continue; //首先处理都为空的情况,直接进入下一次循环//再处理不对称的情况if(l == NULL && r != NULL) return false;else if(l != NULL && r == NULL) return false;else if(l->val != r->val) return false;//最后按照顺序将当前结点的子结点压入栈中que.push(l->left);que.push(r->right);que.push(l->right);que.push(r->left);}return true;
    }
    

    迭代相对于递归的写法更复杂一些,我认为将结点成对的入栈,再成对的取出进行对比是本题的核心思想。

最后

因为二叉树是面试中常考的数据结构,对二叉树的处理也是手撕代码中出现频率较高的,需要熟练掌握,所以要经常回来复习一下!

代码随想录第十五天 二叉树层序遍历 226、101相关推荐

  1. 代码随想录第二十五天|组合、电话号码的字母组合

    代码随想录第二十五天|216.17不熟 Leetcode 216. 组合总和 III Leetcode 17. 电话号码的字母组合 Leetcode 216. 组合总和 III 题目链接: 组合总和 ...

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

    层序遍历 参考文章:代码随想录 解题思路: 层序遍历一个二叉树.就是从左到右一层一层的去遍历二叉树.这种遍历的方式和我们之前讲过的都不太一样. 需要借用一个辅助数据结构即队列来实现,队列先进先出,符合 ...

  3. 代码随想录第二十五天|261.组合总和、17.电话号码的字母组合

    261.组合总和 找出所有相加之和为 n 的 k 个数的组合.组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字. class Solution { private:vector& ...

  4. 代码随想录【day 14 二叉树】| 层序遍历 226.翻转二叉树 101.对称二叉树

    代码随想录[day 14 二叉树]| 层序遍历 226.翻转二叉树 101.对称二叉树 层序遍历 卡哥文解 视频讲解 题目链接:102.二叉树的层序遍历 解题思路 代码实现 题目链接:107.二叉树的 ...

  5. 【LeetCode】专题一 二叉树层序遍历

    二叉树层序遍历 在本文中,我将会选取LeetCode上二叉树层序遍历的多道例题,并给出解答,通过多道题我们就可以发现,二叉树的层序遍历并不复杂,并且有着共通点. 102. 二叉树的层序遍历 给你二叉树 ...

  6. DS-第五章-二叉树的遍历

    数据结构二叉树遍历总结⭐⭐⭐ DS-第五章-二叉树的遍历⭐⭐⭐ 数据结构二叉树遍历总结⭐⭐⭐ 二叉树的概念 遍历 习题分析与代码 二叉树的遍历与线索二叉树 先序遍历 递归先序遍历 非递归算法 中序遍历 ...

  7. 二叉树层序遍历_求二叉树的层序遍历

    题目描述 给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, 该二叉树层序遍历的结果是 [ [3], [9,20], ...

  8. 牛客-二叉树层序遍历

    牛客-二叉树层序遍历 #include <stdio.h> #include <queue> #include <stack> #include <math. ...

  9. 数据结构:二叉树层序遍历和判断是否为完全二叉树

    层序遍历 从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第二层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的节点的过程. while(队列!=NULL) ...

  10. 二叉树层序遍历分层[递归迭代两种思想+三种解法]

    层序遍历分层的递归迭代解法 前言 一.二叉树层序遍历分层 二.递归与迭代 总结 参考文献 前言 层序遍历作为二叉树遍历的基本遍历,一般来说只能用迭代来解.但是分层输出则既可用迭代,又可配合level用 ...

最新文章

  1. 调侃 -- 刚入职时的单纯
  2. ifndef/define/endif——主要目的是防止头文件的重复包含和编译
  3. 实例演示使用HiBench对Hadoop集群进行基准测试
  4. oracle usehash,/*+use_hash(t1 t2)*/的神奇
  5. 2019-03-12-算法-进化(合并两个有序数组)
  6. python集合用法_Python 集合(Set)
  7. ios开发网络学习:一:NSURLConnection发送GET,POST请求
  8. BDTC 2019 | 七个开发者能干多大的事?​
  9. xcode swift_CocoaPods Swift XCode教程
  10. AndroidGUI24:TabHost常用技巧
  11. windows 下安装securecrt 绿色版
  12. 计算机科学 院士 高校,快报!第5轮学科评估计算机科学与技术评委会名单,看有谁上榜了...
  13. 疑难杂症、易混淆、易遗忘的知识点记录
  14. 华为路由器学习指南_BGP_路由反射器与联盟
  15. SMART-DOC使用总结
  16. 计算机视觉算法——基于Anchor Free的目标检测网络总结
  17. linux wps2016_2016年十大Linux新闻报道
  18. 计算机视觉学习 BOW模型图像搜索
  19. Vim实用技巧高清完整版PDF中文
  20. 分享130个ASP源码,总有一款适合您

热门文章

  1. Neo4j之导入CSV大文件 periodic commit
  2. python笔记之json报错
  3. js 格式化prettier配置_Prettier 代码格式化插件 -- 配置翻译
  4. 苹果计算机做视频教程,Mac版Final Cut Pro x使用技巧及视频教程
  5. 一看就懂的保姆级教程:open vn设置 (亲测通过)
  6. 山东理工大学ACM平台题答案关于C语言 1228 两数组最短距离
  7. DeFi新玩法丨一文教你玩转NFT碎片化协议Fractional
  8. link rel=canonical概念和用法(增加页面权重,利于排名)
  9. 政府大数据服务,跑马圈地正当时
  10. PDF文件有密码怎么取消加密