【C/C++】429. N 叉树的层序遍历

482 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情


题目链接:429. N 叉树的层序遍历

题目描述

给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。

树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

提示:

  • 树的高度不会超过 1000
  • 树的节点总数在 [0, 10^4] 之间

示例 1:

narytreeexample.png

输入: root = [1,null,3,2,4,null,5,6]
输出: [[1],[3,2,4],[5,6]]

示例 2:

sample_4_964.png

输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]

整理题意: 题意很好理解,也就是让我们对树上的节点值逐层输出。

解题思路分析

首先我们看到题目给了我们一棵树(一般遇到图和树的题,通常情况都会使用到搜索和遍历),考虑搜索的话,搜索有两种,DFS(深度优先搜索)和BFS(广度优先搜索),题目要求我们层序遍历,也就是一层一层的增加,所以我们优先选择广度优先搜索,在广度优先搜索的每一轮中,我们会遍历同一层的所有节点。

具体地,我们首先把根节点 root 所在的层数和根节点一起放入队列中,这里把层数放入队列是为了方便取出元素时判断该元素是属于当前层还是下一层的元素,如果发现取出的元素层数大于当前层数,说明当前层数的元素已经取完了,已经开始遍历下一层的元素了。那么考虑当前节点的儿子节点是哪一层的元素呢,很明显是当前节点所在层数的下一层,所以我们在将当前节点的儿子节点压入队列的时候,把儿子所在的层数定义为当前节点所在层数+1即可。我们可以用一个临时列表来存放当前层节点的值,当遍历到下一层的第一个元素时,临时列表中就存放了当前层所有节点的值,此时将临时列表中的所有元素放入答案数组,然后清空临时列表,继续下一层的遍历。这样一来,当整个广度优先搜索完成后,我们就可以得到层序遍历的结果。

需要注意的是:当根节点为空的情况,我们需要特殊处理。

复杂度分析

时间复杂度: O(n)O(n),其中 nn 是树中包含的节点个数。在广度优先搜索的过程中,我们需要遍历每一个节点恰好一次。

空间复杂度: O(n)O(n),即为队列需要使用的空间。在最坏的情况下,树只有两层,且最后一层有 n1n−1 个节点,此时就需要 O(n)O(n) 的空间。

代码实现

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        //创建答案数组并初始化清空数组
        vector<vector<int>> ans;
        ans.clear();
        //创建队列并清空初始化队列
        queue<pair<Node*, int>> que; 
        while(que.size()) que.pop();
        //特判当根节点为空的时候返回空数组
        if(root == NULL) return ans;
        //将根节点压入队列,并将根节点所在的层数设置为第0层
        que.push(make_pair(root, 0));
        //创建用于存放某一层的临时数组并初始化清空数组
        vector<int> temp;
        temp.clear();
        //k表示当前层数
        int k = 0;
        //bfs层序遍历
        while(que.size()){
            //取出当前队首元素
            pair<Node*, int> now = que.front();
            que.pop();
            //判断当前队首元素所在的层数是否大于当前层数
            if(now.second > k){
                //将当前层的所有元素放入答案数组
                ans.push_back(temp);
                //清空临时数组,准备存放下一层元素
                temp.clear();
                //将层数设置为下一层
                k++;
            }
            //将当前层元素先放入临时数组
            temp.push_back(now.first->val);
            //将下一层的元素压入队列
            int Size = now.first->children.size();
            for(int i = 0; i < Size; i++){
                que.push(make_pair(now.first->children[i],now.second + 1));
            }
        }
        //注意最后一层的元素还未压入答案数组
        if(temp.size()) ans.push_back(temp);
        return ans;
    }
};

总结

题意很容易理解,对树形结构需要有一定了解,以及需要掌握基本的广度和深度搜索算法,那么对于本题来说就没有什么难度了,核心思想就是通过广度优先搜索来达到逐层递增的目的,从而能够实现层序遍历。当然这题使用深度优先搜索也是可以的,记录好每个节点所在的层数即可,最后按照每个节点所在的层数进行排序即可。


结束语

学再多写作技巧,也不如提起笔来写下第一行字;看再多跑步指南,也不如穿上跑鞋迈开第一步。当你找准方向不再犹豫,把脑中的想法转化为实际的行动,距离目标就已经近了一大步。