郑州快速建站模板,做笑话网站,做个购物网站多少钱,wordpress 谷歌加速二叉树的层次遍历经典问题
一、层次遍历简介
广度优先遍历又称层次遍历#xff0c;过程如下#xff1a; 层次遍历就是从根节点开始#xff0c;先访问根节点下面一层全部元素#xff0c;再访问之后的层次#xff0c;图里就是从左到右一层一层的去遍历二叉树#xff0c… 二叉树的层次遍历经典问题
一、层次遍历简介
广度优先遍历又称层次遍历过程如下 层次遍历就是从根节点开始先访问根节点下面一层全部元素再访问之后的层次图里就是从左到右一层一层的去遍历二叉树先访问3之后访问的左右子孩子9和20之后分别访问9和20的左右子孩子[8,13]和[15,17]最后得到结果[3,9,20,8,13,15,17]。 这里的问题是怎么将遍历过的元素的子孩子保存一下呢例如访问9时其左右子孩子8和13应该先存一下直到处理20之后才会处理。使用队列来存储能完美解决上述问题例如上面的图中 思考该过程不复杂如果能将树的每层次分开了是否可以整点新花样首先能否将每层的元素顺序给反转一下呢能否奇数行不变只将偶数行反转呢能否将输出层次从低到root逐层输出呢再来既然能拿到每一层的元素了能否找到当前层最大的元素最小的元素最右的元素右视图最左的元素左视图)整个层的平均值 很明显都可以这么折腾有啥用呢没啥用但这就是层次遍历的高频算法题这就是LeetCode里经典的层次遍历题 102.二叉树的层序遍历 107.二叉树的层次遍历II 199.二叉树的右视图 637.二叉树的层平均值 429.N叉树的前序遍历 515.在每个树行中找最大值 116.填充每个节点的下一个右侧节点指针 117.填充每个节点的下一个右侧节点指针l 103锯齿层序遍历 除此之外在深度优先的题目里有些仍然会考虑层次遍历的实现方法。 二、基本的层序遍历与变换 2.1 层序遍历基础版
最简单的情况仅仅层序遍历并输出所有元素 利用前面讲到的借助队列的方法来实现
ListIntegersimpleLevelorder(TreeNode root){ifroot null){return new ArrayListInteger();}ListIntegerres new ArrayListInteger();LinkedListTreeNode queue new LinkedListTreeNode();//将根节点放入队列中然后不断遍历队列queue.add(root);//有多少元素执行多少次while (queue.size()0){//获取当前队列的长度这个长度相当于当前这一层的节点个数TreeNode t queue.remove();res.add(t.val);ift.left ! null){queue.add(t.left);}if(t.right null){queue.add(t.right);}}return res;
}2.2 二叉树的层序遍历模版非常重要
。 注意与前面相比要区分每一层 如何判断某一层遍历完了可以设定一个size变量来标记。size表示某一层的元素个数只要元素出队size-1.当size0时该层已经遍历完了。(代码里的做法与这里殊途同归) 然后此时队里的元素个数为下一层元素的个数因此让size标记为下一层的元素个数即可处理下一层了。 最后把每一层遍历到的结点放入一个结果集中将其返回即可
class Solution {public ListListInteger levelOrder(TreeNode root) {if(root null) return new ArrayListListInteger();//创建集合和队列ListListInteger list new ArrayList();LinkedListTreeNode queue new LinkedList();//将根结点放入队列方便进入循环queue.add(root);while(queue.size() 0){//everylist集合用来记录某一层的所有元素ListInteger everylist new ArrayList();//size记录某一层的元素个数int size queue.size();//从队头遍历某一层的所有元素并把下一层的元素存放到队尾for(int i 0; i size; i){TreeNode t queue.remove();everylist.add(t.val);if(t.left ! null)queue.add(t.left);if(t.right ! null)queue.add(t.right);}//此时i size,该层所有元素都遍历完了list.add(everylist);}return list;}
}2.3 层序遍历-自底往上
LeetCode107.给定一个二叉树返回其节点值自底向上的层序遍历。即按从叶子节点所在层到根节点所在的层逐层从左向右遍历)。例如给定的二叉树与结果为下图 实现的代码几乎与正常的层序遍历相同只在list.add(0,everylist)这里把后面遍历的层次放到list的前面实现自底往上的效果。
为了降低在结果列表的头部添加一层节点值的列表的时间复杂度结果列表可以使用链表的结构即创建list时把ArrayList改成LinkedList。在链表头部添加一层节点值的列表的时间复杂度是O(1)。
class Solution {public ListListInteger levelOrderBottom(TreeNode root) {if(root null) return new LinkedListListInteger();ListListInteger list new LinkedList();LinkedListTreeNode queue new LinkedList();queue.add(root);while(queue.size() 0){ListInteger everylist new ArrayList();int size queue.size();for(int i 0; i size; i){TreeNode t queue.remove();everylist.add(t.val);if(t.left ! null)queue.add(t.left);if(t.right ! null)queue.add(t.right);}list.add(0,everylist);}return list;}
}2.4 二叉树的锯齿形层次遍历
LeetCode103题要求是给定一个二叉树返回其节点值的锯齿形层序遍历。即先从左往右再从右往左进行下一层遍历以此类推层与层之间交替进行)。 例如给定二叉树[3,9,20nul,null,15,7] 依旧是对2.2对代码进行改写。因为这里有时是从左到右有时是从右到左自然可以想到把代码里的队列改成双端队列然后再设置过参数判断元素存放位置。 如果从左至右我们每次将被遍历到的当前层元素插入至双端队列的末尾。如果从右至左我们每次将被遍历到的元素插入至双端队列的头部。
class Solution {public ListListInteger zigzagLevelOrder(TreeNode root) {if(root null) return new ArrayListListInteger();ListListInteger list new LinkedList();QueueTreeNode queue new LinkedList();queue.add(root);Boolean judgeleft true;while(queue.size() 0){//创建成双端队列DequeInteger everylist new LinkedList();int size queue.size();for(int i 0; i size; i){TreeNode t queue.remove();//从左到右放队尾if(judgeleft) everylist.offerLast(t.val);//从右到左放队首else everylist.offerFirst(t.val);if(t.left ! null)queue.add(t.left);if(t.right ! null)queue.add(t.right);}judgeleft !judgeleft;//把双端队列转类型list.add(new LinkedListInteger(everylist));}return list;}
}2.5 N叉树的层序遍历
LeetCode.429给定一个N叉树返回其节点值的层序遍历。即从左到右逐层遍历树的序列化输入是用层序遍历每组子节点都由null值分隔参见示例) N叉树的定义如下就是一个值加一个列表其类型仍然是Node: 这个也是102的扩展很简单的广度优先与二叉树的层序遍历基本一样借助队列即可实现。只有在保存当前结点的孩子时不是左右孩子有N个可以使用增强for循环来遍历
class Solution {public ListListInteger levelOrder(Node root) {if(root null)return new ArrayListListInteger();ListListInteger list new ArrayList();QueueNode queue new LinkedList();queue.add(root);while(queue.size() 0){ListInteger everylist new ArrayList();int size queue.size();for(int i 0; i size; i){Node t queue.remove();everylist.add(t.val);//与2.2唯一不同之处,利用增强for循环遍历所有孩子for(Node node1: t.children) {if(node1 ! null) queue.add(node1);}}list.add(everylist);}return list;}
}三、几个处理每层元素的题目
如果我们拿到了每一层的元素那是不是可以利用一下造几个题呢例如每层找最大值、平均值、最右侧的值呢当然可以。LeetCode.里就有三道非常明显的题目。 515.在每个树行中找最大值 637.二叉树的层平均值 199.二叉树的右视图 3.1 在每个树行中找最大值
LeetCode515题目要求给定一棵二叉树的根节点root,请找出该二叉树中每一层的最大值。 与模版相比在while循环中不需要创建另外一个集合只需要用max记录最大值然后添加进list集合即可
class Solution {public ListInteger largestValues(TreeNode root) {if(root null) return new ArrayListInteger();ListInteger maxlist new ArrayList();QueueTreeNode queue new LinkedList();queue.add(root);while(queue.size() 0){int max Integer.MIN_VALUE;int size queue.size();for(int i 0; i size; i){TreeNode t queue.remove();max Math.max(max,t.val);if(t.left ! null) queue.add(t.left);if(t.right ! null) queue.add(t.right);}maxlist.add(max);}return maxlist;}
}3.2 在每个树行中找平均值
LeetCode637要求给定一个非空二叉树返回一个由每层节点平均值组成的数组 这些题目其实都差不多一个思路只要中间一些处理修改一下就行。这道题就把每层元素的和记录下来除以元素个数就行
class Solution {public ListDouble averageOfLevels(TreeNode root) {ListDouble list new ArrayList();if(root null) return list;QueueTreeNode queue new LinkedList();queue.add(root);while(queue.size() 0){int size queue.size();double sum 0;for(int i 0; i size; i){TreeNode t queue.remove();sum t.val;if(t.left ! null) queue.add(t.left);if(t.right ! null) queue.add(t.right);}list.add(sum/size);}return list;}
}3.3 二叉树的右视图
LeetCode199题目要求是给定一个二叉树的根节点root,想象自己站在它的右侧按照从顶部到底部的顺序返回从右侧所能看到的节点值。例如 这道题只要把每层最后一个元素保存起来即可
class Solution {public ListInteger rightSideView(TreeNode root) {ListInteger list new ArrayList();if(root null) return list;QueueTreeNode queue new LinkedList();queue.add(root);while(queue.size() 0){int size queue.size();for(int i 0; i size; i){TreeNode t queue.remove();if(size - 1 i) list.add(t.val);if(t.left ! null) queue.add(t.left);if(t.right ! null) queue.add(t.right);}}return list;}
}3.4 最底层最左边
上面这个层次遍历的思想可以方便的解决LeetCode513.二叉树最底层最左边的值的问题给定一个二叉树的根节点root,请找出该二叉树的最底层最左边节点的值。假设二叉树至少有一个节点。 如果是正常遍历是从左到右那最后会遍历到最底层最右边与题目正好相反。所以我们在遍历存储下一层元素的时候可以先保存右边的节点再保存左边的节点。这样遍历就是从右到左题目就解出来啦。
class Solution {public int findBottomLeftValue(TreeNode root) {//可以记录值也可记录节点最后返回值int num 0;QueueTreeNode queue new LinkedList();queue.add(root);while(queue.size() 0){int size queue.size();for(int i 0; i size; i){TreeNode t queue.remove();num t.val;if(t.right ! null) queue.add(t.right);if(t.left ! null) queue.add(t.left);}}return num;}
}