这是悦乐书的第165次更新,第167篇原创

01 看题和准备

今天介绍的是LeetCode算法题中Easy级别的第24题(顺位题号是107)。给定二叉树,返回其节点值的自下而上级别顺序遍历(即从左到右,逐层逐层)。例如:

给定二叉树[3,9,20,null,null,15,7],

    3
/ \
9 20
/ \
15 7

返回其自下而上的级别顺序遍历:[[15,7],[9,20],[3]]。

本次解题使用的开发工具是eclipse,jdk使用的版本是1.8,环境是win7 64位系统,使用Java语言编写和测试。

02 第一种解法

特殊情况:当传入的二叉树为空时,返回我们新定义的空List即可。

正常情况:从示例最后要求输出的结果来看,根节点是数组的最后一位元素,如果是自顶向下遍历节点,我们可以使用队列,借助其先进先出的特点,一层一层遍历节点,将每一层遍历的节点值存入List中,再将List放入List2中,最后再倒序遍历List2存入List3中,List3就是最后的结果。

public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> list2 = new ArrayList<>();
if (root == null) {
return list2;
}
List<Integer> list = new ArrayList<Integer>();
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
list = new ArrayList<Integer>();
Queue<TreeNode> tem = new LinkedList<>();
while (!q.isEmpty()) {
TreeNode t = q.poll();
list.add(t.val);
if (t.left != null) {
tem.add(t.left);
}
if (t.right != null) {
tem.add(t.right);
}
}
list2.add(list);
q = tem;
}
List<List<Integer>> list3 = new ArrayList<>();
for(int i=list2.size()-1; i >= 0; i--){
list3.add(list2.get(i));
}
return list3;
}

遍历节点的处理方法和昨天那道求最长路径的写法类似,借助队列先进先出的特点,从左往右依次循环。

03 第二种解法

我们可以将第一种解法再优化下,不再创建新的队列来存新的一层的节点。和昨天那道题的写法类似,借助队列的size来作为判断条件。

public List<List<Integer>> levelOrderBottom2(TreeNode root) {
List<List<Integer>> list2 = new ArrayList<>();
if (root == null) {
return list2;
}
List<Integer> list = new ArrayList<Integer>();
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
list = new ArrayList<Integer>();
int n = q.size();
while (n-- > 0) {
TreeNode t = q.poll();
list.add(t.val);
if (t.left != null) {
q.offer(t.left);
}
if (t.right != null) {
q.offer(t.right);
}
}
list2.add(list);
}
List<List<Integer>> list3 = new ArrayList<>();
for(int i=list2.size()-1; i >= 0; i--){
list3.add(list2.get(i));
}
return list3;
}

04 第三种解法

上面两种解法都是使用新的List来存储List2倒序遍历的值作为最后结果返回,既然是先进后出的特点,我们可以使用栈来存储每遍历一层节点存入的List,再使用栈的pop方法出栈存入新的List。

public List<List<Integer>> levelOrderBottom3(TreeNode root) {
List<List<Integer>> list2 = new ArrayList<>();
if (root == null) {
return list2;
}
List<Integer> list = new ArrayList<Integer>();
Stack<List<Integer>> stack = new Stack<List<Integer>>();
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
list = new ArrayList<Integer>();
int n = q.size();
while (n-- > 0) {
TreeNode t = q.poll();
list.add(t.val);
if (t.left != null) {
q.offer(t.left);
}
if (t.right != null) {
q.offer(t.right);
}
}
stack.add(list);
}
while (!stack.isEmpty()) {
list2.add(stack.pop());
}
return list2;
}

05 第四种解法

上面的三种都是使用遍历的方式,那我们可不可以使用递归的方法遍历每一层的节点值?显然是可以的,我们可以使用层数作为标记,来判断现阶段处于那一层,从而来决定是新建一个List还是取已存在的List往里面存入新的节点值。

public List<List<Integer>> levelOrderBottom4(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<List<Integer>> node = new ArrayList<List<Integer>>();
viewTree(root, res, 0);
for (int i=res.size()-1; i>=0; i--) {
node.add(res.get(i));
}
return node;
} public void viewTree(TreeNode root, List<List<Integer>> res, int deep) {
if(root == null)
return;
if (res.size() <= deep) {
List<Integer> node = new ArrayList<Integer>();
node.add(root.val);
res.add(node);
} else {
List<Integer> node = (List<Integer>)res.get(deep);
node.add(root.val);
}
viewTree(root.left, res, deep+1);
viewTree(root.right, res, deep+1);
}

从根节点开始,先递归获取根节点左子节点及其子节点的节点值,然后再递归获取根节点右子节点及其子节点的节点值。

06 验证与测试

对于上面四种解法,我们选取了一个四层的二叉树来作为测试数据,测试代码如下:

public static void main(String[] args) {
Easy_107_BinaryTreeLevelOrderTraversalII instance = new Easy_107_BinaryTreeLevelOrderTraversalII();
TreeNode t = new TreeNode(1);
TreeNode t2 = new TreeNode(2);
TreeNode t3 = new TreeNode(3);
TreeNode t4 = new TreeNode(4);
TreeNode t5 = new TreeNode(5);
TreeNode t6 = new TreeNode(6);
TreeNode t7 = new TreeNode(7);
TreeNode t8 = new TreeNode(8);
t.left = t2;
t.right = t3;
t2.left = t4;
t2.right = t5;
t3.left = t6;
t3.right = t7;
t7.left = t8;
long start = System.nanoTime();
List<List<Integer>> result = instance.levelOrderBottom(t);
long end = System.nanoTime();
System.out.println("levelOrderBottom---输出:"+result.toString()+" , 用时:"+(end-start)/1000+"微秒");
long start2 = System.nanoTime();
List<List<Integer>> result2 = instance.levelOrderBottom2(t);
long end2 = System.nanoTime();
System.out.println("levelOrderBottom2---输出:"+result2.toString()+" , 用时:"+(end2-start2)/1000+"微秒");
long start3 = System.nanoTime();
List<List<Integer>> result3 = instance.levelOrderBottom3(t);
long end3 = System.nanoTime();
System.out.println("levelOrderBottom3---输出:"+result3.toString()+" , 用时:"+(end3-start3)/1000+"微秒");
long start4 = System.nanoTime();
List<List<Integer>> result4 = instance.levelOrderBottom4(t);
long end4 = System.nanoTime();
System.out.println("levelOrderBottom4---输出:"+result4.toString()+" , 用时:"+(end4-start4)/1000+"微秒");
}

测试结果如下:

levelOrderBottom---输出:[[8], [4, 5, 6, 7], [2, 3], [1]] , 用时:446微秒
levelOrderBottom2---输出:[[8], [4, 5, 6, 7], [2, 3], [1]] , 用时:24微秒
levelOrderBottom3---输出:[[8], [4, 5, 6, 7], [2, 3], [1]] , 用时:55微秒
levelOrderBottom4---输出:[[8], [4, 5, 6, 7], [2, 3], [1]] , 用时:23微秒

因为只是采用单一数据测试,样本数量过少,无法得出太过准确的结论,但还是可以明显看出解法二和解法四其他条件一样的情况下用时是最少的。

07 小结

以上就是全部内容,如果大家有什么好的解法思路、建议或者其他问题,可以下方留言交流,点赞、留言、转发就是对我最大的回报和支持!

LeetCode算法题-Binary Tree Level Order Traversal II(Java实现)的更多相关文章

  1. LeetCode算法题-N-ary Tree Level Order Traversal(Java实现)

    这是悦乐书的第225次更新,第238篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第92题(顺位题号是429).给定n-ary树,返回其节点值的级别顺序遍历.(即,从左到 ...

  2. 【一天一道LeetCode】#107. Binary Tree Level Order Traversal II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 来源: htt ...

  3. 【LeetCode】107. Binary Tree Level Order Traversal II (2 solutions)

    Binary Tree Level Order Traversal II Given a binary tree, return the bottom-up level order traversal ...

  4. leetcode 107 Binary Tree Level Order Traversal II ----- java

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  5. 【LeetCode】107. Binary Tree Level Order Traversal II 解题报告 (Python&C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:DFS 方法二:迭代 日期 [LeetCode ...

  6. 【LeetCode】107 - Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  7. LeetCode OJ 107. Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  8. LeetCode OJ:Binary Tree Level Order Traversal II(二叉树的层序遍历)

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  9. 【LeetCode OJ】Binary Tree Level Order Traversal II

    Problem Link: https://oj.leetcode.com/problems/binary-tree-level-order-traversal-ii/ Use BFS from th ...

随机推荐

  1. C#多线程的几种方法详解示例

    这里主要介绍了c#使用多线程的几种方式,通过示例学习c#的多线程使用方式,大家参考使用吧! 1 进程.线程.同步.异步的概念 2 回顾委托,开始异步 3 异步多线程的三大特点 异步多线程都觉得很厉害, ...

  2. 【转载】ASP.NET生成图片的缩略图

    图片处理是C#程序开发中时常会涉及到的一个业务,除了图像的上传.保存以及下载等功能外,根据上传的图片生成一个缩略图也是常见业务,在C#语言中,可以通过Image类提供的相关方法对图片进行操作,如指定宽 ...

  3. Tomcat日志设定

    1    Tomcat 日志概述 Tomcat 日志信息分 为 两 类 : 一.是运行中的日志,它主要 记录 运行的一些信息,尤其是一些异常 错误 日志信息 .二.是 访问 日志信息,它 记录 的 访 ...

  4. Jquery操作ul的一些操作笔记

    1.html标记 <ul id="attachText"> <li data-text="111"><a href="# ...

  5. vb.net 数字大写

    Private Function RMBChinese(ByVal Rmb As Double) As String Dim Rmbexp As String  Dim Rmbda As String ...

  6. React.cloneElement

    作用: 克隆react element, 并传递props, 和children React.cloneElement( element, [props], [...children] ) // ch ...

  7. HDU6187(对偶图生成树)

    Destroy Walls Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)T ...

  8. 二、Laravel手动下载安装及初始化配置(此处以Laravel5.2为例)

    1.下载安装Laravel5.2的几种方法 —— 一键安装包下载: —— http://www.golaravel.com/download/ —— github下载 —— https://githu ...

  9. Python国内豆瓣源

    Python国内豆瓣源 https://pypi.doubanio.com/simple/

  10. IE6不兼容问题

    IE6不兼容问题 一.选择器兼容问题          1.交集选择器从IE7以上兼容(div.special): 2.儿子选择器(>):IE7开始兼容,IE6不兼容. 3.序选择器(first ...