这周偷个懒,拿到简单题来练练手,刚好我的dfs和bfs很薄弱
题目链接:https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/
1. 题目
1)题目简述
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
2)样例
输入:root = [1,null,3,2,4,null,5,6]
输出:3
样例可视化
3)提示部分
- 树的深度不会超过
1000
。 - 树的节点数目位于
[0, 104]
之间。
4)注意事项
-
首先这是一个N叉树,和之前学过的二叉树以及单链表不同,每一个节点其子节点的个数是不知道的,像单链表的下一个节点就1一个,二叉树就一个左右指针,但是N叉树的子节点个数是未知的,所以其子节点的存储方式应该是数组或者容器去存储
-
树节点的定义代码
class Node { public: // 成员变量 // 节点值 int val; // 子节点 vector<Node*> children; // 默认构造函数 Node() {} // 含参构造当前节点值 Node(int _val) { val = _val; } // 含参构造,包含子节点 Node(int _val, vector<Node*> _children) { val = _val; children = _children; } };
-
然后根据提示,树的深度不会超过1000, 数的节点最大只有104个,这表明我们使用dfs或者bfs完全是没问题的。
2. DFS——深度优先搜索解法
再讲dfs之前,先看看什么是搜索算法
搜索算法是利用计算机的高性能来有目的的穷举一个问题解空间的部分或所有的可能情况,从而求出问题的解的一种方法。现阶段一般有枚举算法、深度优先搜索、广度优先搜索、A*算法、回溯算法、蒙特卡洛树搜索、散列函数等算法。在大规模实验环境中,通常通过在搜索前,根据条件降低搜索规模;根据问题的约束条件进行剪枝;利用搜索过程中的中间解,避免重复计算这几种方法进行优化。{出自百度百科}
今天,我们将使用dfs,和bfs分别去求解这两个问题。
什么是深度优先?
其实就是字面意思,以题目为例,就是优先遍历树的子节点,题目中的样例,节点1有3个节点,假如先遍历节点3,然后遍历节点5,节点5的子节点位空,即没有子节点,这时再遍历6,然后又没有子节点,再遍历节点2 和 4。
那么在编程上我们应该怎样去实现?
我们可以采用递归函数,每一次递归的时候优先遍历第一个子节点,对每一次递归完后去更新此时的最大深度。
具体代码
class Solution {
public:
// dfs深度优先搜索
int maxDepth(Node* root) {
if(root == nullptr)
{
return 0;
}
// 声明子节点最大深度
int maxChildDepth = 0;
// 声明子节点指针数组
auto children = root->children;
// 循环子节点
for(auto child : children)
{
// 递归得到当前子节点的深度
int childDepth = maxDepth(child);
// 动态更新最大深度
maxChildDepth = max(maxChildDepth, childDepth);
}
return maxChildDepth + 1;
}
};
3. BFS——广度优先搜索
和dfs不同优先遍历子节点不同,bfs实际上优先遍历当前层数的节点
还是以题目为样例,3的同一层节点有2和4,遍历了2,3,4后才去遍历3的子节点
1. 小知识
在广度优先搜索的解法中,我们通常会使用队列才存储遍历的节点,详见代码
class Solution {
public:
// bfs 队列
int maxDepth(Node* root) {
if(root == nullptr)
{
return 0;
}
// 队列存储节点
queue<Node *> qu;
qu.push(root);
int ans = 0;
while(!qu.empty())
{
// size 记录当前层的尺寸 —— 节点个数
int size = qu.size();
while(size > 0)
{
// 循环得到当前层的节点
Node* node = qu.front();
// 队首节点出队
qu.pop();
// 获取移除的队首节点的子节点
vector<Node *> children = node->children;
// 将子节点入队
for(auto child : children)
{
qu.push(child);
}
// 当前层节点个数-1
size--;
}
// 一层遍历完,深度+1
ans++;
}
return ans;
}
};
4. 总结
BFS和DFS都是常用的遍历搜索方法,但是它们的区别简单来讲就是dfs是一条路一直走到底再回退,再走到底,可借助栈、递归的形式实现,而bfs则是围着根节点一层层地往外遍历。正常情况下二者的复杂度相同,dfs要比bfs好写一些,因为在递归的时候本身就有调用栈的空间,而bfs则要老老实实排队。