小数乘法计算题100道_leetcode题库c语言

小数乘法计算题100道_leetcode题库c语言LeetCode算法题-Binary Tree Level Order Traversal II(Java实现)

大家好,又见面了,我是你们的朋友全栈君。

这是悦乐书的第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 小结

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

转载于:https://www.cnblogs.com/xiaochuan94/p/9927092.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107205.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Linux 命令(139)—— nslookup 命令

    Linux 命令(139)—— nslookup 命令1.命令简介nslookup(NameServerLookup)是一种网络管理命令,用于从DNS服务器查询域名、IP或其他DNS记录信息。nslookup有两种工作模式,交互模式和非交互模式。在交互模式下,用户可以向域名服务器查询各类主机、域名的信息,或者输出域名中的主机列表。在非交互模式下,针对一个主机或域名仅仅获取特定的名称或所需信息。进入交互模式有两种方式:(1)直接输入nslookup命令,不加任何参数,此时nslookup会连接到默认的域名服务器(/etc/resol

    2022年10月19日
    4
  • tomcat7官网下载

    tomcat7官网下载1.官网地址:tomcat.apache.org,进入后点击Tomcat72.选择不同的类型,以“64-bitWindowszip”为例3.保存文件,确定4.解压后,进入bin目录,双击startup.bat,出现下图5.打开浏览器,输入127.0.0.1:8080,出现下图,安装成功转载于:https://my.oschina.net/u/4052883/blog/29915522…

    2022年5月19日
    35
  • HTTPS和HTTP的区别是什么?

    HTTPS和HTTP的区别是什么?

    2021年10月14日
    52
  • Python中的for i in range(range()函数的for循环)如何使用,详细介绍[通俗易懂]

    Python中的for i in range(range()函数的for循环)如何使用,详细介绍[通俗易懂]range函数的for循环1.定义2.两种形式3.可理解性例子4.range函数的特性详述4.1 左闭右开4.2 开始值默认为04.3 步长值默认为14.4 range函数的反向输出5.与列表list的使用6.range与list的区别1.定义range是一个函数,它返回的是一个可迭代对象,大多使用于for循环中。相当于C/Java里面的for(inti=m;i<n;…

    2022年8月12日
    8
  • centos环境搭建postfix邮件服务

    centos环境搭建postfix邮件服务

    2021年5月30日
    123
  • spss k-means聚类分析_K均值聚类及其应用

    spss k-means聚类分析_K均值聚类及其应用SPSS聚类分析:K均值聚类分析一、概念:(分析-分类-K均值聚类)1、此过程使用可以处理大量个案的算法,根据选定的特征尝试对相对均一的个案组进行标识。不过,该算法要求您指定聚类的个数。如果知道,您可以指定初始聚类中心。您可以选择对个案分类的两种方法之一,要么迭代地更新聚类中心,要么只进行分类。可以保存聚类成员、距离信息和最终聚类中心。还可以选择指定一个变量,使用该变量的值…

    2022年10月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号