当前位置: 首页 > news >正文

【LeetCode】429.N叉树的层序遍历(图文详解,三种方法,java实现)

题目

链接:

image-20200627123321053

分析

方法一:利用队列实现广度优先搜索

我们要构造一个 sub-lists 列表,其中每个 sub-list 是树中一行的值。行应该按从上到下的顺序排列。

因为我们从根节点开始遍历树,然后向下搜索最接近根节点的节点,这是广度优先搜索。我们使用队列来进行广度优先搜索,队列具有先进先出的特性。

在这里使用栈是错误的选择,栈应用于深度优先搜索。

让我们在树上使用基于队列的遍历算法,看看它的作用。这是你应该记住的一个基本算法。

List<Integer> values = new ArrayList<>();
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
    Node nextNode = queue.remove();
    values.add(nextNode.val);
    for (Node child : nextNode.children) {
        queue.add(child);
    }
}

用一个列表存放节点值,队列存放节点。首先将根节点放到队列中,当队列不为空时,则在队列取出一个节点,并将其子节点添加到队列中。

让我们看看这个算法遍历树时我们得到了什么结果。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们可以看到它从左到右,并且从上到写顺序遍历节点。下一步,我们将研究如何如何在这个算法的基础上保存每一层的列表。

算法:
上面的基本算法在一定程度上帮助了我们解决这道题目,但是我们还需要保存每一层的列表,并且在根节点为空时正常工作。

再构造下一层的列表时,我们需要创建新的子列表,然后将该层的所有节点的值插入到列表中。一个很好的方法时在 while 循环体开始时记录队列的当前大小 size。然后用另一个循环来处理 size 数量的节点。这样可以保证 while 循环在每一次迭代处理一层。

使用队列十分重要,如果使用 VectorListArray 的话,我们删除元素需要 O(n)O(n) 的时间复杂度。而队列删除元素只需要 O(1)O(1) 的时间。

// This code is a modified version of the code posted by
// #zzzliu on the discussion forums.
class Solution {

    public List<List<Integer>> levelOrder(Node root) {      
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            List<Integer> level = new ArrayList<>();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Node node = queue.poll();
                level.add(node.val);
                queue.addAll(node.children);
            }
            result.add(level);
        }
        return result;
    }
}

复杂度分析

  • 时间复杂度:O(n)。n 指的是节点的数量。
  • 空间复杂度:O(n).

方法二:简化的广度优先搜索

算法:

// This code is a modified version of the code posted by
// #zzzliu on the discussion forums.
class Solution {

    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;

        List<Node> previousLayer = Arrays.asList(root);

        while (!previousLayer.isEmpty()) {
            List<Node> currentLayer = new ArrayList<>();
            List<Integer> previousVals = new ArrayList<>();
            for (Node node : previousLayer) {
                previousVals.add(node.val);
                currentLayer.addAll(node.children);
            }
            result.add(previousVals);
            previousLayer = currentLayer;
        }

        return result;
    }
}

复杂度分析

  • 时间复杂度:O(n)。n 指的是节点的数量。
  • 空间复杂度:O(n),我们的列表包含所有节点。

方法三:递归

算法:
我们可以使用递归来解决这个问题,通常我们不能使用递归进行广度优先搜索。这是因为广度优先搜索基于队列,而递归运行时使用堆栈,适合深度优先搜索。但是在本题中,我们可以以不同的顺序添加到最终列表中,只要我们知道节点在哪一层并确保在那一层的列表顺序正确就可以了。

class Solution {

    private List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> levelOrder(Node root) {
        if (root != null) traverseNode(root, 0);
        return result;
    }

    private void traverseNode(Node node, int level) {
        if (result.size() <= level) {
            result.add(new ArrayList<>());
        }
        result.get(level).add(node.val);
        for (Node child : node.children) {
            traverseNode(child, level + 1);
        }
    }
}

复杂度分析

  • 时间复杂度:O(n)。n 指的是节点的数量
  • 空间复杂度:正常情况O*(log*n),最坏情况 O(n)。运行时在堆栈上的空间。

相关文章:

  • 【LeetCode】648.单词替换(前缀树多种解法,java实现)
  • 【LeetCode】421. 数组中两个数的最大异或值(哈希集合,字典树,详细图文解释)
  • 【LeetCode】200.岛屿数量(dfs+bfs+并查集,超详细图文解释)
  • python实现强智科技教务系统抢课(两种方法)
  • [ChromeApp]指南!让你的谷歌浏览器好用十倍!
  • 【LeetCode】279.完全平方数(四种方法,不怕不会!开拓思维)
  • 【LeetCode】739.每日温度(5种方法,详细图解)
  • 【LeetCode】733.图像渲染(深度优先搜索,java实现)
  • 【LeetCode】56.合并区间(贪心算法,java实现)
  • 【LeetCode】旋转矩阵(原地选择+翻转两种方法,java实现)
  • 计算机基础(一):二进制详解
  • 计算机基础(二):压缩算法
  • 计算机基础(四):控制硬件
  • 【LeetCode】5.最长回文子串(中心扩散法,动态规划,超详细图文,java实现)
  • 【LeetCode】151.翻转字符串里的单词(三种方法,java实现)
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • axios 和 cookie 的那些事
  • Git的一些常用操作
  • IDEA常用插件整理
  • in typeof instanceof ===这些运算符有什么作用
  • MySQL主从复制读写分离及奇怪的问题
  • Vue2.0 实现互斥
  • 安装python包到指定虚拟环境
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 基于游标的分页接口实现
  • 简单基于spring的redis配置(单机和集群模式)
  • 盘点那些不知名却常用的 Git 操作
  • 前嗅ForeSpider中数据浏览界面介绍
  • 设计模式 开闭原则
  • 深入浏览器事件循环的本质
  • 《天龙八部3D》Unity技术方案揭秘
  • #预处理和函数的对比以及条件编译
  • (13)Hive调优——动态分区导致的小文件问题
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (蓝桥杯每日一题)love
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • .NET 事件模型教程(二)
  • .net和jar包windows服务部署
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [100天算法】-二叉树剪枝(day 48)
  • [3300万人的聊天室] 作为产品的上游公司该如何?
  • [android] 手机卫士黑名单功能(ListView优化)
  • [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
  • [cocos2d-x]关于CC_CALLBACK
  • [Docker]十二.Docker consul集群搭建、微服务部署,Consul集群+Swarm集群部署微服务实战
  • [gdc19]《战神4》中的全局光照技术
  • [hdu 2896] 病毒侵袭 [ac自动机][病毒特征码匹配]
  • [Java][方法引用]构造方法的引用事例分析
  • [oeasy]python001_先跑起来_python_三大系统选择_windows_mac_linux
  • [Python] Ubuntu12.04LTS