2024年C C++最新力扣429 - N叉树的层序遍历【BFS+DFS】(1),2024年最新GitHub标星9K的Google官方MVP+RxC C++项目详解

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

2、分步详解(重要代码)

  • 首先看到🔎题目要我们返回的是一个vector<vector<>>的类型 ,所以定义一个结果集的容器来承装,然后对于BFS层次遍历,我们一般都会使用队列来解决,因此需要再定义一个二叉树类型的队列,然后先对根结点进行判断,若存在根结点,先将其入队
 queue<Node\*> qu;
 vector<vector<int>> result;
 if(root != NULL)    qu.push(root);

  • 其次,就是要在队不为空时进行每层的遍历判断,一个循环便是一层,首先取到遍历当前层是队列的大小,然后去进行一个单层的遍历,取出当前队列的首元素,并将其出队,之后此结点放入小结果集,也就是为了存放一层的所有结点所定义的vec容器。
  • 后面就是比较关键的一步,要对遍历到结点的孩子结点进行一个再次的内层遍历,去判断其是否有孩子结点,若有,则将它们全部入队
 //将遍历到的孩子结点入队
 for(int i = 0;i < node->children.size(); ++i)
     if(node->children[i])    qu.push(node->children[i]);
     //若有孩子结点,则将其入队,继而继续出队,而不是放进容器

结构顺序大致是这样

请添加图片描述

  • 在存放完这一层的所有结点之后,因为孩子结点已入队,所以队列不为空,继续while循环的执行,这个时候就是下一层即是孩子结点所在的层的遍历,孩子结点可能又会有孩子结点,一层层遍历下去, 直到碰到叶子结点为止

3、整体代码(Java、C++)

class Solution {
public:
    vector<vector<int>> levelOrder(Node\* root) {
        queue<Node\*> qu;
        vector<vector<int>> result;
        if(root != NULL)    qu.push(root);

        while(!qu.empty())
        {
            int sz = qu.size();
            vector<int> vec;

            for(int i = 0;i < sz; ++i)
            {
                Node\* node = qu.front();
                qu.pop();
                vec.push\_back(node->val);

                //将遍历到的孩子结点入队
                for(int i = 0;i < node->children.size(); ++i)
                    if(node->children[i])    qu.push(node->children[i]);
                    //若有孩子结点,则将其入队,继而继续出队,而不是放进容器
            }
            result.push\_back(vec);
        }
        return result;
    }
};

再给一种Java版本的

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        Queue<Node> qu = new LinkedList<>();
        List<List<Integer>> result = new ArrayList<>();
        if(root != null)    qu.offer(root);

        while(!qu.isEmpty())
        {
            int sz = qu.size();
            List<Integer> vec = new ArrayList<>();
            while(sz > 0)
            {
                Node node = qu.poll();
                vec.add(node.val);
                qu.addAll(node.children);
                sz--;
            }
            result.add(vec);
        }
        return result;
    }
}

  • 语言都是想通的,一般刷题的话我C++用的多一些,Java有时候也会用。这里整体思路也是一致,只是但是循环用的是while而已,add()是添加的意思,addAll()便是将所有此类型的结点添加,也就是将所有孩子结点入队即可,sz–直到其为0为止,就是单层的结点数量

解法二:DFS(深度优先搜索)

1、万能模板(!!!)

不仅是BFS有万能模板,DFS也有,一样先展示给大家🔦

class Solution {
public:
    void order(TreeNode\* cur, vector<vector<int>>& result, int depth)
    {
        if (cur == nullptr) return;
        if (result.size() == depth) result.push\_back(vector<int>());
        result[depth].push\_back(cur->val);
        order(cur->left, result, depth + 1);
        order(cur->right, result, depth + 1);
    }
    vector<vector<int>> levelOrder(TreeNode\* root) {
        vector<vector<int>> result;
        int depth = 0;
        order(root, result, depth);
        return result;
    }
};

2、分步详解

if(cur == NULL)    return;

void dfs(Node\* cur,int dep,vector<vector<int>>& res)

dfs(root,0,result);


  • 首先讲解一下递归参数,一个是Node*结点类型,主要用用于判断当前所遍历到的结点,开始是用于判断根节点是否为空,若为空,则直接返回,dep就是遍历到的此树的深度,也就是用于控制在每一层的结点,将他们放入小结果集,最后的res则是大结果集,用于接收最后整棵树的结果,这里有一个细节要注意,就是这个&取址,准确的说应该是引用,只有加上了这个,才能将递归函数的中所收集的结果传出去,否则只会出现如下情况,主函数接口中就接受不到最终的结果,即传不出去
    请添加图片描述
  • 然后是递归内部的主要代码,res[dep]便是上面讲到的控制每一层的遍历并加入这一层的结点的值,也就是cur->val,因为这个dep在递归其孩子结点的时候是会增加的,所以将其设置为数组的下标,当这个dep == res.size()时,是递归出口,将vector<>()是开辟一个小结果集,将所收集每一层的结点放入这个大结果集
 if(dep == res.size())
     res.push\_back(vector<int>());
 res[dep].push\_back(cur->val);

  • 最后,便是对于孩子结点的遍历,采取for循环的方式进行遍历,这里的auto&是正常for循环的简写,这样比较方便,也简洁易懂,设置引用变量x,对cur->children所指向的孩子结点做一一的遍历,dfs继续递归,进入函数,这里可以看到dep每递归一次便会增加,也是相当于将其添加进结果集的一个标记
for(auto& x : cur->children)
    dfs(x,dep + 1,res);

3、整体代码(Java、C++)

class Solution {
private:
    void dfs(Node\* cur,int dep,vector<vector<int>>& res)
    {
        if(cur == NULL)    return;
        if(dep == res.size())
            res.push\_back(vector<int>());
        res[dep].push\_back(cur->val);

        //递归孩子结点
        for(auto& x : cur->children)
            dfs(x,dep + 1,res);
    }
public:
    vector<vector<int>> levelOrder(Node\* root) {
        vector<vector<int>> result;
        dfs(root,0,result);

        return result;
    }
};

一样提供一下Java版本

class Solution {
    private void dfs(Node cur,int level,List<List<Integer>> res)
    {
        if(cur == null)     return;
        List<Integer> list = res.size() <= level ? new ArrayList<Integer>() : res.get(level);
        list.add(cur.val);      //添加当前结点到每一树层

        if(level >= res.size())
            res.add(list);      //若level首次到达下一树层,则上一树层放入结果集

        //孩子结点递归
        for(Node ChildrenNode : cur.children)
            dfs(ChildrenNode, level + 1, res);
    }
    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> result = new ArrayList<>();
        dfs(root,0,result);

        return result;
    }
}

略微做一些讲解🔨

Java里面的容器主要还是用ArrayList,内部类型名称要写成Integer,不能写成Int,其他思路也是相似,就是这里在递归内部用了一个三元运算符(主要是可以装一下),比较长一些,也就是判断一下当前的level值是否到达容器的大小,若是,则新开辟一个小的结果集用于放入新的结点,若还未到,则使用get()获取到当前level位置所在值的结点

list.add(cur.val); 

这个就是将当前做遍历到的结点放入新开辟的小结果集的一个操作。其他操作均是一个意思,便不做说明

总结与拓展

看完了两种BFS和DFS对N叉树的遍历,你有没有对这两种遍历搜索算法有了一个初步的了解呢,DFS的话在回溯里比较多,BFS在图里比较多,但是对于二叉树的层次遍历,这两种方法用的都挺多的,大家记住我提供的这个模板就可以秒杀这下面的题了💥

102.二叉树的层序遍历

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

g-mvZkOGeu-1715561354331)]
[外链图片转存中…(img-QVRh7ZJ1-1715561354332)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值