【剑指Offer】个人学习笔记_32_从上到下打印二叉树 IIIIII
目录
- I
- 题目:
- [剑指 Offer 32 - I. 从上到下打印二叉树](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/)
- 题目分析
- 初始解答:
- 学习他人:
- 方法一:
- 方法二:
- 方法三:
- 方法四:
- Stream简介
- II
- 题目:
- [剑指 Offer 32 - II. 从上到下打印二叉树 II](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/)
- 题目分析
- 初始解答:
- 学习他人:
- 方法一:
- 方法二:
- 方法三:
- Java中的queue和deque
- III
- 题目:
- [剑指 Offer 32 - III. 从上到下打印二叉树 III](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/)
- 题目分析
- 初始解答:
- 学习他人:
- 方法一:
- 方法二:
- 方法三:
- 方法四:
- 总结
刷题日期:19:5225 星期四2021年4月8日
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
I
题目:
剑指 Offer 32 - I. 从上到下打印二叉树
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
例如:
给定二叉树: [3,9,20,null,null,15,7]
,
3/ \9 20/ \15 7
[3,9,20,15,7]
题目分析
首先因为树的深度不确定,所以返回数组的长度也不一定,可以考虑用一个链表先存放数据,然后遍历链表定义数组返回。要么就得用类似于add这种添加命令不断加上新的子树节点。
其次因为是树的问题,首先想到递归解决,不断获取左右子树的节点内容,存储到返回数组。
层序遍历,又称广度优先搜索
初始解答:
因为暂时想不到解决数组长度的办法,而且这种遍历方式记的也不是很清楚,参考书和其他人的解答。
书上提到了用队列来解决问题,因为每次提出数据都需要先把它的左右子树放入队列。
层序遍历,参考了方法一
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public int[] levelOrder(TreeNode root) {//先考虑特殊情况if (root == null) return new int[0];//定义队列Queue<TreeNode> que = new LinkedList<TreeNode>();//定义数组List<Integer> list = new ArrayList<Integer>();//先把根节点放进去que.add(root); //入队,这里不放root.val,因为入队的就是节点while(!que.isEmpty()){ //这种特殊类型的数据是不是都有这个方法TreeNode node = que.poll(); //出队操作,建立树节点存放当前节点list.add(node.val); //列表的add属性,不用知道长度if(node.left != null) que.add(node.left); //先左if(node.right != null) que.add(node.right); //再右//所有节点都进入队列}//出队完毕,转换列表为数组return list.stream().mapToInt(Integer::intValue).toArray();//将Integer类型list复制为int数组 只不过使用了java8的stram新特性 //建议去了解一下stream 当然也可以直接写循环复制//流方法,不深究了}
}
效率比较低 执行结果:通过
显示详情
执行用时:4 ms, 在所有 Java 提交中击败了17.35%的用户
内存消耗:39 MB, 在所有 Java 提交中击败了5.02%的用户
参考了K神方法三后更直观的写法
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public int[] levelOrder(TreeNode root) {//先考虑特殊情况if (root == null) return new int[0];//定义队列,直接赋值写法,第二个尖括号里面的内容可省Queue<TreeNode> que = new LinkedList<>(){{ add(root); }};//定义数组ArrayList<Integer> list = new ArrayList<>();while(!que.isEmpty()){ //这种特殊类型的数据是不是都有这个方法TreeNode node = que.poll(); //出队操作,建立树节点存放当前节点list.add(node.val); //列表的add属性,不用知道长度if(node.left != null) que.add(node.left); //先左if(node.right != null) que.add(node.right); //再右//所有节点都进入队列}//出队完毕,转换列表为数组//更直观的写法//定义数组int[] res = new int[list.size()];//确定长短//列表数据转移到数组for(int i = 0; i < list.size(); i++) res[i] = list.get(i);return res;}
}
大概是没有调用流的原因,速度快了很多。执行结果: 通过
显示详情
执行用时:1 ms, 在所有 Java 提交中击败了99.74%的用户
内存消耗:38.7 MB, 在所有 Java 提交中击败了17.31%的用户
大家的思路都差不多,学习,主要还是队列这种的基本初始化都不清楚。
再默写一遍记忆写法,尤其是队列和列表的定义方法
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public int[] levelOrder(TreeNode root) {if (root == null) return new int [0];Queue<TreeNode> q = new LinkedList<>();q.add(root);ArrayList<Integer> l = new ArrayList<>();while (!q.isEmpty()) {TreeNode node = q.poll();l.add(node.val);if (node.left != null) q.offer(node.left);if (node.right != null) q.offer(node.right);}int [] res = new int[l.size()];for (int i = 0; i < l.size(); i++) res[i] = l.get(i);return res;}
}
学习他人:
方法一:
AmmoMercyL1 2020-04-08
简单的层序遍历
class Solution {public int[] levelOrder(TreeNode root) {if(root==null)return new int[0];Queue<TreeNode> queue=new LinkedList<TreeNode>();List<Integer> list=new ArrayList<Integer>();queue.add(root);while(!queue.isEmpty()){TreeNode node=queue.poll();list.add(node.val);if(node.left!=null)queue.add(node.left);if(node.right!=null)queue.add(node.right);}return list.stream().mapToInt(Integer::intValue).toArray();}
}
方法二:
wydxry 1 天前
执行结果: 通过 显示详情 执行用时: 1 ms , 在所有 Java 提交中击败了 99.74% 的用户 内存消耗: 38.5 MB , 在所有 Java 提交中击败了 76.48% 的用户
class Solution {public int[] levelOrder(TreeNode root) {List<Integer> res_=new ArrayList<Integer>();Queue<TreeNode> q = new LinkedList<TreeNode>();if(root==null){int[] res=new int[0];return res;}q.offer(root);while(q.peek()!=null){TreeNode tmp=q.poll();if(tmp.left!=null){q.offer(tmp.left);}if(tmp.right!=null){q.offer(tmp.right);}res_.add(tmp.val);}int[] res=new int[res_.size()];for(int i=0;i<res.length;i++){res[i]=res_.get(i);}return res;}
}
方法三:
题目要求的二叉树的 从上至下 打印(即按层打印),又称为二叉树的 广度优先搜索(BFS)。
BFS 通常借助 队列 的先入先出特性来实现。
K神 作者:jyd
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/solution/mian-shi-ti-32-i-cong-shang-dao-xia-da-yin-er-ch-4/
来源:力扣(LeetCode)
class Solution {public int[] levelOrder(TreeNode root) {if(root == null) return new int[0];Queue<TreeNode> queue = new LinkedList<>(){{ add(root); }};ArrayList<Integer> ans = new ArrayList<>();while(!queue.isEmpty()) {TreeNode node = queue.poll();ans.add(node.val);if(node.left != null) queue.add(node.left);if(node.right != null) queue.add(node.right);}int[] res = new int[ans.size()];for(int i = 0; i < ans.size(); i++)res[i] = ans.get(i);return res;}
}
方法四:
夜尽天明…L1
(编辑过)2020-06-29
大佬(指K神),我看到网上的博客说,Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。 修改完的代码如下:
class Solution {public int[] levelOrder(TreeNode root) {if (root == null) // 空树则返回空数组return new int[0];Queue<TreeNode> q = new LinkedList<> (); // 借助一个队列,通过 BFS 实现按层遍历二叉树ArrayList<Integer> tmp =new ArrayList<> (); // 申请一个动态数组 ArrayList 动态添加节点值q.offer(root); // 根结点先入队while (q.size() != 0) {TreeNode node = q.poll(); // 取出当前队首元素tmp.add(node.val); if(node.left != null) q.offer(node.left); // 左子节点入队if(node.right != null) q.offer(node.right); // 右子节点入队}// 将 ArrayList 转为 int数组并返回int[] res = new int[tmp.size()];for (int i=0; i<res.length; i++) {res[i] = tmp.get(i);}return res;}
}
Stream简介
作者:我是你的小眼睛儿
链接:https://www.jianshu.com/p/9fe8632d0bc2
来源:简书
- Java 8引入了全新的Stream API。这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。
- stream是对集合对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。
- 只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
II
题目:
剑指 Offer 32 - II. 从上到下打印二叉树 II
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
例如:
给定二叉树: [3,9,20,null,null,15,7]
,
3/ \9 20/ \15 7
[[3],[9,20],[15,7]
]
题目分析
与第一题相比,增加了难度,返回的是分行的列表,那么难点就在于,如何定义二维的列表,只要这里通了,求解思路是类似的。
初始解答:
正好再一次复习相关存储方式的定义,一些地方没有了解过所以留下空白。
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {//特殊情况if (root == null) return new List [0]; //不知道这种写法对不对//同样定义队列Queue<TreeNode> q = new LinkedList<>() {{ add(root); }};//定义列表,这次得是二维ArraylList<Integer> l = new ArraylList<>();int x = 0; //得有数据代表层数while (! q.isEmpty()) {TreeNode node = q.pull();l.add(node.val);if (node.left != null) q.offer(node.left);if (node.right != null) q.offer(node.right);}return l //如果l直接定义成二维列表的话,直接返回即可}
}
看了评论后大家好像并没有借鉴多少上一题的思路,也没有二维列表这一说法,不过方法二还是比较接近的,进行修改。
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {//定义列表,这次得是二维List<List<Integer>> res = new ArrayList<>();//特殊情况if (root == null) return res; //不知道这种写法对不对//定义双向队列Deque<TreeNode> q = new ArrayDeque<>() {{ add(root); }};while (! q.isEmpty()) { //循环一次多一层的数据int size = q.size();//定义列表,每一层一个一维List<Integer> l = new ArrayList<>();// size对应在该层的子树个数,思路很巧妙while (size-- > 0) { //循环一次减一TreeNode node = q.poll();l.add(node.val);if (node.left != null) q.offer(node.left);if (node.right != null) q.offer(node.right);}res.add(l); //在列表的基础上加列表}return res; //如果l直接定义成二维列表的话,直接返回即可}
}
就是效率一般 执行结果:通过
显示详情
执行用时:2 ms, 在所有 Java 提交中击败了8.26%的用户
内存消耗:38.8 MB, 在所有 Java 提交中击败了15.44%的用户
K神的方法也是这种思路,不过第二层循环感觉还是K神比较简单一些
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {//定义列表,这次得是二维List<List<Integer>> res = new ArrayList<>();//定义队列Queue<TreeNode> q = new LinkedList<>();//特殊情况if (root != null) q.add(root); while (! q.isEmpty()) { //循环一次多一层的数据//定义列表,每一层一个一维List<Integer> l = new ArrayList<>();// size对应在该层的子树个数,思路很巧妙for (int i = q.size(); i > 0; i--) { //为什么必须是递减的顺序// for (int i = 0; i < q.size(); i++) { //这样就会解答错误,因为在循环中q.size()已经改变,for循环第一项只用一次,如果放在第二项,就会连续判断新的size,所以出错TreeNode node = q.poll();l.add(node.val);if (node.left != null) q.offer(node.left);if (node.right != null) q.offer(node.right);}res.add(l); //在列表的基础上加列表}return res; //如果l直接定义成二维列表的话,直接返回即可}
}
少用了一个size,效果立马就好了。执行结果:通过
显示详情
执行用时:1 ms, 在所有 Java 提交中击败了94.50%的用户
内存消耗:38.7 MB, 在所有 Java 提交中击败了46.42%的用户
学习方法一的递归解法:
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {List<List<Integer>> res = new ArrayList(); //双层列表,注意这里没有尖括号public List<List<Integer>> levelOrder(TreeNode root) {recur(root,0);return res;}public void recur(TreeNode root, int k) {if (root != null) {if (res.size() <= k) res.add(new ArrayList());res.get(k).add(root.val);recur(root.left, K+1);recur(root.right, K+1);}}
}
明明就是按着来的,就是报错
几乎一样的代码上面的不行,下面的就可以
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {List<List<Integer>> res = new ArrayList(); //双层列表,注意这里没有尖括号public List<List<Integer>> levelOrder(TreeNode root) {recur(root, 0);return res;}public void recur(TreeNode root, int k) {if (root != null) {if (res.size() <= k) res.add(new ArrayList());res.get(k).add(root.val);recur(root.left, K+1);recur(root.right, K+1);}}
}
/
class Solution {List<List<Integer>> res = new ArrayList();public List<List<Integer>> levelOrder(TreeNode root) {recur(root, 0);return res;}public void recur(TreeNode root, int k) {if (root != null) {if (res.size() <= k) res.add(new ArrayList());res.get(k).add(root.val);recur(root.left, k+1);recur(root.right, k+1);}}
}
最后找到bug在输入k+式shift按早了,打成K+了,不知道你们能不能看出来大小写k和K的区别,我是瞎了已经
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {List<List<Integer>> res = new ArrayList(); //双层列表,注意这里没有尖括号public List<List<Integer>> levelOrder(TreeNode root) {recur(root, 0);return res;}public void recur(TreeNode root, int k) {if (root != null) {if (res.size() <= k) res.add(new ArrayList());res.get(k).add(root.val);recur(root.left, k+1);recur(root.right, k+1);//好家伙,小写k和大写K的区别}}
}
速度是真快 执行结果:通过
显示详情
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:39 MB, 在所有 Java 提交中击败了5.00%的用户
学习他人:
方法一:
活动假人 2020-04-06
java 递归层次遍历
class Solution {List<List<Integer>> node=new ArrayList();public List<List<Integer>> levelOrder(TreeNode root) {lei(root,0);return node;}public void lei(TreeNode root,int k){if(root!=null){if(node.size()<=k)node.add(new ArrayList());node.get(k).add(root.val);lei(root.left,k+1);lei(root.right,k+1);}}
}
方法二:
fireworksL1
2020-10-11
class Solution {/**层次遍历*/public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();if(root == null){return res;}Deque<TreeNode> queue = new ArrayDeque<>();queue.offer(root);while(!queue.isEmpty()){int size = queue.size();List<Integer> list = new ArrayList<>();while(size-- > 0){TreeNode node = queue.poll();list.add(node.val);if(node.left != null){queue.offer(node.left);}if(node.right != null){queue.offer(node.right);}} res.add(list);}return res;}
}
方法三:
K神 作者:jyd
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/solution/mian-shi-ti-32-ii-cong-shang-dao-xia-da-yin-er-c-5/
来源:力扣(LeetCode)
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {Queue<TreeNode> queue = new LinkedList<>();List<List<Integer>> res = new ArrayList<>();if(root != null) queue.add(root);while(!queue.isEmpty()) {List<Integer> tmp = new ArrayList<>();for(int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();tmp.add(node.val);if(node.left != null) queue.add(node.left);if(node.right != null) queue.add(node.right);}res.add(tmp);}return res;}
}
Java中的queue和deque
III
题目:
剑指 Offer 32 - III. 从上到下打印二叉树 III
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
例如:
给定二叉树: [3,9,20,null,null,15,7]
,
3/ \9 20/ \15 7
[[3],[20,9],[15,7]
]
题目分析
这种是不是就得用栈和队列来交替解答了,先队列再栈,最后再合并。
初始解答:
感觉就是很绝望,一道题原来能玩出来这么多花样,参考上一道题改的
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {Queue<TreeNode> queue = new LinkedList<>();List<List<Integer>> res = new ArrayList<>();if(root != null) queue.add(root);int ord = 0;while(!queue.isEmpty()) {List<Integer> tmp = new ArrayList<>();for(int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();tmp.add(node.val);if (ord % 2 == 1) {if(node.left != null) queue.add(node.left);if(node.right != null) queue.add(node.right);} else {if(node.right != null) queue.add(node.right);if(node.left != null) queue.add(node.left);}}ord ++;res.add(tmp);}return res;}
}
解答出现了错误 执行结果:
解答错误显示详情
输入:[1,2,3,4,null,null,5]
输出:[[1],[3,2],[5,4]]
预期结果:[[1],[3,2],[4,5]]
换用Java自带方法,参考方法一
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {//定义列表,这次得是二维List<List<Integer>> res = new ArrayList<>();//定义队列Queue<TreeNode> q = new LinkedList<>();//特殊情况int level=1;if (root != null) q.add(root); while (! q.isEmpty()) { //循环一次多一层的数据//定义列表,每一层一个一维List<Integer> l = new ArrayList<>();// size对应在该层的子树个数,思路很巧妙for (int i = q.size(); i > 0; i--) { //为什么必须是递减的顺序// for (int i = 0; i < q.size(); i++) { //这样就会解答错误,因为在循环中q.size()已经改变,for循环第一项只用一次,如果放在第二项,就会连续判断新的size,所以出错TreeNode node = q.poll();l.add(node.val);if (node.left != null) q.offer(node.left);if (node.right != null) q.offer(node.right);}if(level%2==0) Collections.reverse(l);//反转方法res.add(l); //在列表的基础上加列表level++;}return res; //如果l直接定义成二维列表的话,直接返回即可}
}
效率不高 执行结果:通过
显示详情
执行用时:2 ms, 在所有 Java 提交中击败了26.96%的用户
内存消耗:38.9 MB, 在所有 Java 提交中击败了6.50%的用户
不折腾了,有兴趣分析的直接看方法四K神的分析即可
学习他人:
方法一:
offer来碗里L1 2021-03-20
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res=new ArrayList<>();if(root==null) return res;Queue<TreeNode> q=new LinkedList<>();q.offer(root);int level=1;while(!q.isEmpty()){List<Integer> list=new ArrayList<>();int size=q.size();for(int i=0;i<size;i++){TreeNode node=q.poll();list.add(node.val);if(node.left!=null) q.offer(node.left);if(node.right!=null) q.offer(node.right);}if(level%2==0) Collections.reverse(list);res.add(list);level++;}return res;}
方法二:
WUTerL1
2021-02-23
详细注释+代码
/*** 要求:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,* 第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推* @param root 二叉树根结点* @return 结果* 方法:层序遍历 + 双端队列,奇数层(第一层为1)从首结点到尾结点,依次添加到集合中,新结点依次添加到队列尾部;* 偶数层从尾结点到首结点依次添加到集合中,新结点依次添加到首部*/public static List<List<Integer>> levelOrder(TreeNode root) {// 结果List<List<Integer>> res = new ArrayList<>();// 判空if (root == null) {return res;}// 层序遍历辅助队列Deque<TreeNode> deque = new LinkedList<>();deque.add(root);// 打印顺序标志,初始值表示从左开始boolean isLeft = true;// 遍历二叉树while (!deque.isEmpty()) {// 单独一层的结果List<Integer> ans = new ArrayList<>();// 得到此时队列中结点的个数,即当前层的结点数int count = deque.size();// 遍历队列中的结点,并将下一层的结点入队for (int i = 0; i < count; i++) {// 队列中的元素始终按照每一层的结点的相对位置顺序存储,只是在遍历分别从头结点开始或者从尾结点开始if (isLeft) {// 从头结点开始,并把新结点添加到尾部TreeNode dequeHead = deque.peekFirst();ans.add(dequeHead.val);// 先左后右if (dequeHead.left != null) {deque.addLast(dequeHead.left);}if (dequeHead.right != null) {deque.addLast(dequeHead.right);}// 删除首元素deque.removeFirst();}else {// 从尾结点开始,并且将新结点添加到首部TreeNode dequeHead = deque.peekLast();ans.add(dequeHead.val);// 先右后左if (dequeHead.right != null) {deque.addFirst(dequeHead.right);}if (dequeHead.left != null) {deque.addFirst(dequeHead.left);}// 删除尾元素deque.removeLast();}}// 将单层结果添加到结果集合中res.add(ans);// 顺序取反isLeft = !isLeft;}return res;}
方法三:
麦宇恒 2020-02-15 递归
class Solution {List<List<Integer>> res=new ArrayList<>();public List<List<Integer>> levelOrder(TreeNode root) {helper(root,0);return res;}private void helper(TreeNode root,int level){if(root==null)return;if(res.size()==level){res.add(new ArrayList<>());}if(level%2==0){res.get(level).add(root.val);}else{res.get(level).add(0,root.val);}helper(root.left,level+1);helper(root.right,level+1);}
}
方法四:
K神
方法一:层序遍历 + 双端队列
利用双端队列的两端皆可添加元素的特性,设打印列表(双端队列) tmp ,并规定:
奇数层 则添加至 tmp 尾部 ,
偶数层 则添加至 tmp 头部 。
作者:jyd
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/solution/mian-shi-ti-32-iii-cong-shang-dao-xia-da-yin-er–3/
来源:力扣(LeetCode)
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {Queue<TreeNode> queue = new LinkedList<>();List<List<Integer>> res = new ArrayList<>();if(root != null) queue.add(root);while(!queue.isEmpty()) {LinkedList<Integer> tmp = new LinkedList<>();for(int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();if(res.size() % 2 == 0) tmp.addLast(node.val); // 偶数层 -> 队列尾部else tmp.addFirst(node.val); // 奇数层 -> 队列头部if(node.left != null) queue.add(node.left);if(node.right != null) queue.add(node.right);}res.add(tmp);}return res;}
}
方法二:层序遍历 + 双端队列(奇偶层逻辑分离)
方法一代码简短、容易实现;但需要判断每个节点的所在层奇偶性,即冗余了 NN 次判断。
通过将奇偶层逻辑拆分,可以消除冗余的判断。
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {Deque<TreeNode> deque = new LinkedList<>();List<List<Integer>> res = new ArrayList<>();if(root != null) deque.add(root);while(!deque.isEmpty()) {// 打印奇数层List<Integer> tmp = new ArrayList<>();for(int i = deque.size(); i > 0; i--) {// 从左向右打印TreeNode node = deque.removeFirst();tmp.add(node.val);// 先左后右加入下层节点if(node.left != null) deque.addLast(node.left);if(node.right != null) deque.addLast(node.right);}res.add(tmp);if(deque.isEmpty()) break; // 若为空则提前跳出// 打印偶数层tmp = new ArrayList<>();for(int i = deque.size(); i > 0; i--) {// 从右向左打印TreeNode node = deque.removeLast();tmp.add(node.val);// 先右后左加入下层节点if(node.right != null) deque.addFirst(node.right);if(node.left != null) deque.addFirst(node.left);}res.add(tmp);}return res;}
}
方法三:层序遍历 + 倒序
此方法的优点是只用列表即可,无需其他数据结构。
偶数层倒序: 若 res 的长度为 奇数 ,说明当前是偶数层,则对 tmp 执行 倒序 操作。
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {Queue<TreeNode> queue = new LinkedList<>();List<List<Integer>> res = new ArrayList<>();if(root != null) queue.add(root);while(!queue.isEmpty()) {List<Integer> tmp = new ArrayList<>();for(int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();tmp.add(node.val);if(node.left != null) queue.add(node.left);if(node.right != null) queue.add(node.right);}if(res.size() % 2 == 1) Collections.reverse(tmp);res.add(tmp);}return res;}
}
总结
以上就是本题的内容和学习过程了,变体太多了,这才叫举一反三吧,太强了。
奇偶这个真是妙蛙种子吃着妙脆角进了米奇妙妙屋,妙到家了。
欢迎讨论,共同进步。
【剑指Offer】个人学习笔记_32_从上到下打印二叉树 IIIIII相关推荐
- 剑指offer——面试题23:从上往下打印二叉树
剑指offer--面试题23:从上往下打印二叉树 Solution1: 典型的BFS算法! 思路一开始没想到,按照书上的思路写的答案... 注意:deque是双向队列,在头尾插入都很快! /* str ...
- 剑指offer(Java实现) 从上往下打印二叉树
题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 解题思路 利用队列(链表)辅助实现. 代码实现 import java.util.ArrayList; import java.uti ...
- 剑指offer二十二之从上往下打印二叉树
一.题目 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 二.思路 二叉树的层次遍历,可以借助队列实现.具体思路详见注释. 三.代码 import java.util.ArrayList; i ...
- 剑指offer面试题23:从上到下打印二叉树(树的层序遍历)
题目:从上往下打印出二叉树的每个节点,同一层的结点按照从左往右的顺序打印. 解题思路:二叉树的层序遍历,在打印一个节点的时候,要把他的子节点保存起来打印第一层要把第二层的节点保存起来, 打印第二层要把 ...
- [剑指offer]面试题23:从上往下打印二叉树
面试题23:从上往下打印二叉树 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印.例如输入图4.5中的二叉树,则依次打印出8.6.10.5.7.9.11. 二叉树结点的定义如下 ...
- 剑指Offer - 面试题32 - III. 从上到下打印二叉树 III(BFS,queue+stack)
1. 题目 请实现一个函数按照之字形顺序打印二叉树, 即第一行按照从左到右的顺序打印, 第二层按照从右到左的顺序打印, 第三行再按照从左到右的顺序打印,其他行以此类推. 例如: 给定二叉树: [3,9 ...
- 剑指Offer - 面试题32 - I. 从上到下打印二叉树(按层BFS遍历,queue)
1. 题目 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印. 例如: 给定二叉树: [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回: [3,9 ...
- 剑指offer面试题32 - III. 从上到下打印二叉树 III(二叉树)(BFS)
题目描述 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推. 思路 详见链接 代码 class So ...
- 剑指offer面试题32 - I. 从上到下打印二叉树(二叉树)(BFS)
题目描述 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印. 思路 详见链接 代码 class Solution:def levelOrder(self, root:TreeNode ...
最新文章
- 【高并发】一个工作了7年的朋友去面试竟然被Thread类虐的体无完肤
- 三大缓存框架ehcache、memcache和redis的介绍
- [uEnv.txt]在uEnv.txt文件中使用if语句实现Image/dtb文件切换
- 蓝桥杯 十进制数转八进制数
- Python学习系列day2-python基础
- 格兰杰因果关系检验_混频(mixed frequency)数据的格兰杰因果(Grange causality)检验及其Matlab实现...
- iOS开发-网络-合理封装请求接口
- 图像分类——EfficientNet的学习笔记
- 2022最新版sci和ssci双检索期刊,详细期刊目录值得了解!
- 发电厂计算机监控课,那比水利发电厂监控系统课件.ppt
- Flowchat 流程图在Markdown中的使用(不同编辑器有细微区别)
- 卸载Docker CE
- 通过漫画学习MySQL索引及优化
- 魔教传奇—阿里软件的魔方文化
- QCC---Host configure tools
- 安装iso格式的软件安装程序
- python中文件的导入与导出
- 运用css3新属性transform写的盒子嵌套展开动画效果
- ABAP 发布webservice调用外部webservice
- 数值分析实验 实验3-1 牛顿下山法 python3实现
热门文章
- python pptx库中文文档_python-pptx使用说明
- 给职场年轻人的一些建议
- 电磁兼容(EMC)设计如何融入产品研发流程~系统流程法
- 抢在时间前面的7条捷径阅读笔记
- 聚焦采购数字化,企企通受邀出席中国上海采购-供应链间接采购年会
- 0x00007FF727D8013F 处有未经处理的异常(在 bigship.exe 中): 0xC0000005: 读取位
- web开发中经常使用到的代码(csdn中下载的资源)
- HoloLens开发笔记-制作传送门
- java 声明一个bus类_Java初级阶段测试附带答案
- dpi是什么?如何更改dpi?(仅个人笔记,可能有误)