每日一题:LeetCode-102.二叉树的层序遍历

简介: 每日一题:LeetCode-102.二叉树的层序遍历

每日一题系列(day 03)

前言:

🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈

   🔎🔎如果说代码有灵魂,那么它的灵魂一定是👉👉算法👈👈,因此,想要写出💚优美的程序💚,核心算法是必不可少的,少年,你渴望力量吗😆😆,想掌握程序的灵魂吗❓❗️那么就必须踏上这样一条漫长的道路🏇🏇,我们要做的,就是斩妖除魔💥💥,打怪升级!💪💪当然切记不可😈走火入魔😈,每日打怪,日日累积,终能成圣🙏🙏!开启我们今天的斩妖之旅吧!✈️✈️

LeetCode-102.二叉树的层序遍历

题目:

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例1:

示例2:

注意事项:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

解法一:

  思路:

  说到二叉树的层序遍历,我们第一反应肯定是用广度优先搜索,广搜需要队列存储每一层的节点,当一层节点处理完之后再将本层已处理的节点全部pop掉,接着处理下一层节点,直到处理完毕,深搜便完成了,这里题目要求用二维数组来接收深搜的结果,所以我们可以开个二维数组,在每层节点pop之前,把每层节点记录在一位数组中,最终把一维数组放到二维数组中。每一层的二维数组都代表每一层的节点的遍历结果。

  1、首先,当节点为空的时候我们直接返回空的二维数组。不为空则根据题目要求创建一个二维数组,再创建队列来记录二叉树的每个节点,再将根节点压入到队列中。

  2、节点已经入队,开始处理二叉树。我们知道,二叉树有很多层,所以我们需要一层一层来遍历,每一层处理完后,本层节点也被pop,再处理下一层,其实这就是一个循环的过程。条件是只要不为空就一直处理。

  3、在循环内,创建一个临时一维数组来记录本层所有节点的值,用计数器来记录这层拥有的节点个数,再使用for循环处理每一层的节点。

  4、for循环内,取队头元素,将队头的元素值压入本层的一维数组中,当处理的当前节点时,如果当前节点有子节点,就把下一层的子节点入队,用来下次的遍历,最后再将当前已经处理完了的节点pop出队列。

  5、最后直接返回二维数组即可。

代码实现:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root == NULL)
        vector<vector<int>> ans;//根据题目要求创建一个二维数组
        return vector<vector<int>>();//节点为空直接返回空的二维数组即可
        queue<TreeNode *> q;//创建一个队列用来记录每一层的节点
        TreeNode *node = nullptr;//记录队列的每个节点,便于处理单个节点
        q.push(root);//将根节点压入队列
        while(!q.empty())//只要队列不为空说明这一层还存在节点
        {
            int cnt = q.size();//记录队列节点数量
            vector<int> tmp;//使用tmp数组接收每一层的节点
            for(int i = 0 ; i < cnt ; i++)//处理每层的节点
            {
                node = q.front();//记录取队头节点
                tmp.push_back(node -> val);//在队列这层节点pop之前将节点值压入本层的一维数组,这个一维数组就是这层节点
                if(node -> left) q.push(node -> left);//本层节点的左子树存在就把左孩子入队列,下次处理
                if(node -> right) q.push(node -> right);//本层节点的右子树存在就把右孩子入队列,下次处理
                q.pop();//本层节点处理完,把本层pop掉,处理下一层节点
            }
            ans.push_back(tmp);//将一维数组(本层遍历结果)尾插进二维数组
        }
        return ans;//返回二维数组即可
    }
};

解法二:

  思路:

  其实这题完全可以不用广搜,使用深搜也能进行层序遍历,并且使用深搜的代码会更加简洁一些。使用深搜也就是dfs,那么如何深搜才是关键,其实我们只需要知道每个节点的层数就可以进行深搜了,我们可以直接用节点的层数把深搜的每个节点压入到对应层的数组中。

  1、在深度优先搜索前,我们按照题目要求先创建一个二维数组,然后进行深搜,这里需要注意,dfs的参数首先要传入根节点,在传入从哪层开始处理的层次(从第0层开始处理),最后再传参二维数组的引用。

  2、进入到深搜,如果节点为空的话直接返回。当本层层数与二维数组存储的一维数组数量相等,表示已经处理到当前的层数了,这个时候在二维数组当前层数(下标)插入一个空一维数组。

  3、接下来就将每一层的节点插入到对应层的一维数组中,然后向左子树搜索,左子树为当前层的下一层,所以传参k + 1,然后向右子树搜索,同样层数为k + 1,最后return即可。

代码实现:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void dfs(TreeNode *root, int k, vector<vector<int>> &ans)//传参需要根节点,节点所在层数,以及二维数组的引用传参
    {
        if(root == NULL) return;//根节点为null直接返回
        if(k == ans.size()) ans.push_back(vector<int>());//当当前层数与二维数组存储一维数组数量相同时,表示处理到当前的层数了,对二维数组进行尾插一个空一维数组
        ans[k].push_back(root -> val);//将每一层的节点尾插到每一层的数组里
        dfs(root -> left,  k + 1, ans);//深搜左子树,下一层节点层数要加一
        dfs(root -> right, k + 1, ans);//同样,深搜下一层右子树,层数加一
        return;//深搜结束
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;//创建二维数组
        dfs(root, 0, ans);//进行深搜
        return ans;//返回深搜结果即可
    }
};

  二叉树的层序遍历,我们通常是使用第一种队列的方式进行广度优先搜索,然而用深度优先搜索来对二叉树层序遍历的代码设计感更优美,可读性也更高。

相关文章
|
7月前
|
Go 开发者 索引
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣33 / 81/ 153/154)(Go语言版)
本文深入探讨了LeetCode中四道关于「搜索旋转排序数组」的经典题目,涵盖了无重复和有重复元素的情况。通过二分查找的变形应用,文章详细解析了每道题的解题思路和Go语言实现代码。关键点包括判断有序区间、处理重复元素以及如何缩小搜索范围。文章还总结了各题的异同,并推荐了类似题目,帮助读者全面掌握二分查找在旋转数组中的应用。无论是初学者还是有经验的开发者,都能从中获得实用的解题技巧和代码实现方法。
329 14
|
8月前
|
算法 Go
【LeetCode 热题100】深入理解二叉树结构变化与路径特性(力扣104 / 226 / 114 / 543)(Go语言版)
本博客深入探讨二叉树的深度计算、结构变换与路径分析,涵盖四道经典题目:104(最大深度)、226(翻转二叉树)、114(展开为链表)和543(二叉树直径)。通过递归与遍历策略(前序、后序等),解析每题的核心思路与实现方法。结合代码示例(Go语言),帮助读者掌握二叉树相关算法的精髓。下一讲将聚焦二叉树构造问题,欢迎持续关注!
207 10
|
8月前
|
存储 算法 数据可视化
【二叉树遍历入门:从中序遍历到层序与右视图】【LeetCode 热题100】94:二叉树的中序遍历、102:二叉树的层序遍历、199:二叉树的右视图(详细解析)(Go语言版)
本文详细解析了二叉树的三种经典遍历方式:中序遍历(94题)、层序遍历(102题)和右视图(199题)。通过递归与迭代实现中序遍历,深入理解深度优先搜索(DFS);借助队列完成层序遍历和右视图,掌握广度优先搜索(BFS)。文章对比DFS与BFS的思维方式,总结不同遍历的应用场景,为后续构造树结构奠定基础。
412 10
|
8月前
|
Go
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣437 / 236 )(Go语言版)
本文深入探讨二叉树中路径与祖先问题,涵盖两道经典题目:LeetCode 437(路径总和 III)和236(最近公共祖先)。对于路径总和 III,文章分析了双递归暴力解法与前缀和优化方法,后者通过哈希表记录路径和,将时间复杂度从O(n²)降至O(n)。在最近公共祖先问题中,采用后序遍历递归查找,利用“自底向上”的思路确定最近公共祖先节点。文中详细解析代码实现与核心要点,帮助读者掌握深度追踪技巧,理解树结构中路径与节点关系的本质。这类问题在面试中高频出现,掌握其解法意义重大。
207 4
|
8月前
|
Go 索引 Perl
【LeetCode 热题100】【二叉树构造题精讲:前序 + 中序建树 & 有序数组构造 BST】(详细解析)(Go语言版)
本文详细解析了二叉树构造的两类经典问题:通过前序与中序遍历重建二叉树(LeetCode 105),以及将有序数组转化为平衡二叉搜索树(BST,LeetCode 108)。文章从核心思路、递归解法到实现细节逐一拆解,强调通过索引控制子树范围以优化性能,并对比两题的不同构造逻辑。最后总结通用构造套路,提供进阶思考方向,帮助彻底掌握二叉树构造类题目。
468 9
【LeetCode 43】236.二叉树的最近公共祖先
【LeetCode 43】236.二叉树的最近公共祖先
134 0
【LeetCode 38】617.合并二叉树
【LeetCode 38】617.合并二叉树
102 0
【LeetCode 37】106.从中序与后序遍历构造二叉树
【LeetCode 37】106.从中序与后序遍历构造二叉树
123 0
【LeetCode 34】257.二叉树的所有路径
【LeetCode 34】257.二叉树的所有路径
109 0
【LeetCode 32】111.二叉树的最小深度
【LeetCode 32】111.二叉树的最小深度
114 0