题型:树、图、BFS、DFS
链接:2385. 感染二叉树需要的总时间 - 力扣(LeetCode)
来源:LeetCode
题目描述
给你一棵二叉树的根节点 root
,二叉树中节点的值 互不相同 。另给你一个整数 start
。在第 0
分钟,感染 将会从值为 start
的节点开始爆发。
每分钟,如果节点满足以下全部条件,就会被感染:
- 节点此前还没有感染。
- 节点与一个已感染节点相邻。
返回感染整棵树需要的分钟数。
题目样例
示例 1:
输入:root = [1,5,3,null,4,10,6,9,2], start = 3 输出:4 解释:节点按以下过程被感染: - 第 0 分钟:节点 3 - 第 1 分钟:节点 1、10、6 - 第 2 分钟:节点5 - 第 3 分钟:节点 4 - 第 4 分钟:节点 9 和 2 感染整棵树需要 4 分钟,所以返回 4 。
示例 2:
输入:root = [1], start = 1 输出:0 解释:第 0 分钟,树中唯一一个节点处于感染状态,返回 0 。
提示:
- 树中节点的数目在范围
[1, 105]
内 1 <= Node.val <= 105
- 每个节点的值 互不相同
- 树中必定存在值为
start
的节点
题目思路
乍一看能感觉出来是层序遍历(广度优先遍历),或者说求树的最大深度?
但是他不是树的遍历方式——因为start不一定是root结点
如果是一个图进行,那问题也会简单许多——直接BFS拓扑排序就行,但这是个树,所以可以考虑先把 树转化为图 然后进行BFS
那问题就可以转化为 ①将树转化为图 ② BFS遍历图
将树转化为图可以DFS遍历一次:图的数据结构可以用 vector<int> 来存相连的点的val
转化为图后可以进行从 start 开始的 BFS —- 用queue来存拓扑排序的点的 【相连的点】 。遍历完一次后就可以将【相连的点】添加到 queue 中。
考虑到一个点可能被多个点相连 进而可能被访问多次,可以用 visit 数组来存一下是否被访问过
C++代码
class Solution {
public:
int amountOfTime(TreeNode* root, int start) {
// int存time vector<int> 存孩子/父节点
unordered_map<int,vector<int>>graph;
// lambda定义dfs
function<void(TreeNode *)>dfs = [&](TreeNode * node){
//将左右孩子整合为child
for(TreeNode *child : vector<TreeNode *> {node ->left,node -> right}){
if(child != nullptr){
// 将孩子结点添加到数组中 —— 数组存相连的点
graph[node -> val].push_back(child -> val);
// 将父亲结点添加到数组中 —— 数组存与这个点连接的结点
graph[child -> val].push_back(node -> val);
dfs(child);
}
}
};
// 相当于二维矩阵 来将一个树转化为图
dfs(root);
// 队列存拓扑排序的顺序 但还存遍历的次数
queue<vector<int>> Q;
Q.push({start,0});
//相当于在有图的情况下 进行BFS
// 存储遍历过的点
unordered_set<int> visited;
visited.insert(start);
int time = 0;
while(!Q.empty()){
auto temp =Q.front() ;
Q.pop();
int nodeVal = temp[0];
time = temp[1];
// 遍历点对应的相连的结点
for(int Val : graph[nodeVal]){
if(!visited.count(Val)){
Q.push({Val,time+1});
visited.insert(Val);
}
}
}
return time;
}
};