力扣--2092. 找出知晓秘密的所有专家(Java)
前言:
这是力扣的一道算法题,采用按时间分组 + 图的连通性传播DFS
这是一种 事件驱动 + 图遍历 的混合策略,核心思想是:
秘密只能在「同一时刻」通过「会议网络」传播;不同时间的会议不能互相影响。
理解起来挺简单的,就是分组,然后遍历。
题目:
给你一个整数 n ,表示有 n 个专家从 0 到 n - 1 编号。另外给你一个下标从 0 开始的二维整数数组 meetings ,其中 meetings[i] = [xi, yi, timei] 表示专家 xi 和专家 yi 在时间 timei 要开一场会。一个专家可以同时参加 多场会议 。最后,给你一个整数 firstPerson 。
专家 0 有一个 秘密 ,最初,他在时间 0 将这个秘密分享给了专家 firstPerson 。接着,这个秘密会在每次有知晓这个秘密的专家参加会议时进行传播。更正式的表达是,每次会议,如果专家 xi 在时间 timei 时知晓这个秘密,那么他将会与专家 yi 分享这个秘密,反之亦然。
秘密共享是 瞬时发生 的。也就是说,在同一时间,一个专家不光可以接收到秘密,还能在其他会议上与其他专家分享。
在所有会议都结束之后,返回所有知晓这个秘密的专家列表。你可以按 任何顺序 返回答案。
示例 1:
输入:n = 6, meetings = [[1,2,5],[2,3,8],[1,5,10]], firstPerson = 1
输出:[0,1,2,3,5]
解释:
时间 0 ,专家 0 将秘密与专家 1 共享。
时间 5 ,专家 1 将秘密与专家 2 共享。
时间 8 ,专家 2 将秘密与专家 3 共享。
时间 10 ,专家 1 将秘密与专家 5 共享。
因此,在所有会议结束后,专家 0、1、2、3 和 5 都将知晓这个秘密。
示例 2:
输入:n = 4, meetings = [[3,1,3],[1,2,2],[0,3,3]], firstPerson = 3
输出:[0,1,3]
解释:
时间 0 ,专家 0 将秘密与专家 3 共享。
时间 2 ,专家 1 与专家 2 都不知晓这个秘密。
时间 3 ,专家 3 将秘密与专家 0 和专家 1 共享。
因此,在所有会议结束后,专家 0、1 和 3 都将知晓这个秘密。
示例 3:
输入:n = 5, meetings = [[3,4,2],[1,2,1],[2,3,1]], firstPerson = 1
输出:[0,1,2,3,4]
解释:
时间 0 ,专家 0 将秘密与专家 1 共享。
时间 1 ,专家 1 将秘密与专家 2 共享,专家 2 将秘密与专家 3 共享。
注意,专家 2 可以在收到秘密的同一时间分享此秘密。
时间 2 ,专家 3 将秘密与专家 4 共享。
因此,在所有会议结束后,专家 0、1、2、3 和 4 都将知晓这个秘密。
提示:
2 <= n <= 1051 <= meetings.length <= 105meetings[i].length == 30 <= xi, yi <= n - 1xi != yi1 <= timei <= 1051 <= firstPerson <= n - 1
题目讲解:
本题要求找出所有最终知晓秘密的专家。
初始时,专家 0 和 firstPerson 知道秘密,秘密仅在会议中传播,且同一时间点内所有连通的专家构成信息共享组——只要组内一人知密,全员即刻获知。
关键在于:秘密传播具有严格的时间顺序,不同时间的会议不能跨时段影响。
因此,需先将会议按时间排序,再逐时间点构建无向图,通过 DFS 从已知秘密者出发,标记其所在连通分量的所有成员。
该方法高效利用了图的连通性与事件驱动思想,确保传播逻辑正确且时间复杂度可控。
代码:
class Solution { public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) { Arrays.sort(meetings,(a,b) -> a[2] - b[2]); Set<Integer> havaSecret = new HashSet<>(); havaSecret.add(0); havaSecret.add(firstPerson); int m = meetings.length; for(int i = 0;i<m;){ Map<Integer,List<Integer>> g = new HashMap<>(); int time = meetings[i][2]; for(;i<m && meetings[i][2] == time;i++){ int x = meetings[i][0]; int y = meetings[i][1]; g.computeIfAbsent(x,k -> new ArrayList<>()).add(y); g.computeIfAbsent(y,k -> new ArrayList<>()).add(x); } Set<Integer> vis = new HashSet<>(); for(int x:g.keySet()){ if(havaSecret.contains(x) && !vis.contains(x)){ dfs(x,g,vis,havaSecret); } } } return new ArrayList<>(havaSecret); } private void dfs(int x,Map<Integer,List<Integer>> g,Set<Integer> vis,Set<Integer> havaSecret){ vis.add(x); havaSecret.add(x); for(int y : g.get(x)){ if(!vis.contains(y)){ dfs(y,g,vis,havaSecret); } } } }
代码讲解:
一、初始化
先对二维整数数组meetings,其中meetings进行排序,使用Lambda表达式,对时间排序
建立Hashset,不予许有重复的元素
一开始专家0和专家firstperpon知道秘密,所以需要初始化加入
Arrays.sort(meetings,(a,b) -> a[2] - b[2]); Set<Integer> havaSecret = new HashSet<>(); havaSecret.add(0); havaSecret.add(firstPerson);
二、逻辑实现
先初始化一个散列表,键值对,在嵌套一个list,做一个无向图,表示该时间内有哪些专家在开会,可以互相知晓秘密,然后互相添加到对方的邻接表中
然后是同一个通量中,只要有一个人知道秘密了,其他人就肯定知道秘密
int m = meetings.length; for(int i = 0;i<m;){ Map<Integer,List<Integer>> g = new HashMap<>(); int time = meetings[i][2]; for(;i<m && meetings[i][2] == time;i++){ int x = meetings[i][0]; int y = meetings[i][1]; g.computeIfAbsent(x,k -> new ArrayList<>()).add(y); g.computeIfAbsent(y,k -> new ArrayList<>()).add(x); } Set<Integer> vis = new HashSet<>(); for(int x:g.keySet()){ if(havaSecret.contains(x) && !vis.contains(x)){ dfs(x,g,vis,havaSecret); } }
三、递归
把知道的加入,不知道的继续遍历,递归
private void dfs(int x,Map<Integer,List<Integer>> g,Set<Integer> vis,Set<Integer> havaSecret){ vis.add(x); havaSecret.add(x); for(int y : g.get(x)){ if(!vis.contains(y)){ dfs(y,g,vis,havaSecret); } }
结语:
希望这篇博客可以帮助大家理解,一起加油!每天进步一点点!
更多推荐


所有评论(0)