题型:树、图、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
转化为图后可以进行从 start 开始的 BFS —- 用queue来存拓扑排序的点的 【相连的点】 。遍历完一次后就可以将【相连的点】添加到 queue 中。
考虑到一个点可能被多个点相连 进而可能被访问多次,可以用 visit 数组来存一下是否被访问过
- class Solution {
- public:
- int amountOfTime(TreeNode* root, int start) {
- // int存time vector
存孩子/父节点 - unordered_map<int,vector<int>>graph;
- // lambda定义dfs
- function<void(TreeNode *)>dfs = [&](TreeNode * node){
- //将左右孩子整合为child
- for(TreeNode *child : vector
{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
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;
- }
- };