You are given an integer n
indicating there are n
people numbered from 0
to n - 1
. You are also given a 0-indexed 2D integer array meetings
where meetings[i] = [xi, yi, timei]
indicates that person xi
and person yi
have a meeting at timei
. A person may attend multiple meetings at the same time. Finally, you are given an integer firstPerson
.
Person 0
has a secret and initially shares the secret with a person firstPerson
at time 0
. This secret is then shared every time a meeting takes place with a person that has the secret. More formally, for every meeting, if a person xi
has the secret at timei
, then they will share the secret with person yi
, and vice versa.
The secrets are shared instantaneously. That is, a person may receive the secret and share it with people in other meetings within the same time frame.
Return a list of all the people that have the secret after all the meetings have taken place. You may return the answer in any order.
Example 1:
Input: n = 6, meetings = [[1,2,5],[2,3,8],[1,5,10]], firstPerson = 1 Output: [0,1,2,3,5] Explanation: At time 0, person 0 shares the secret with person 1. At time 5, person 1 shares the secret with person 2. At time 8, person 2 shares the secret with person 3. At time 10, person 1 shares the secret with person 5. Thus, people 0, 1, 2, 3, and 5 know the secret after all the meetings.
Example 2:
Input: n = 4, meetings = [[3,1,3],[1,2,2],[0,3,3]], firstPerson = 3 Output: [0,1,3] Explanation: At time 0, person 0 shares the secret with person 3. At time 2, neither person 1 nor person 2 know the secret. At time 3, person 3 shares the secret with person 0 and person 1. Thus, people 0, 1, and 3 know the secret after all the meetings.
Example 3:
Input: n = 5, meetings = [[3,4,2],[1,2,1],[2,3,1]], firstPerson = 1 Output: [0,1,2,3,4] Explanation: At time 0, person 0 shares the secret with person 1. At time 1, person 1 shares the secret with person 2, and person 2 shares the secret with person 3. Note that person 2 can share the secret at the same time as receiving it. At time 2, person 3 shares the secret with person 4. Thus, people 0, 1, 2, 3, and 4 know the secret after all the meetings.
Constraints:
2 <= n <= 105
1 <= meetings.length <= 105
meetings[i].length == 3
0 <= xi, yi <= n - 1
xi != yi
1 <= timei <= 105
1 <= firstPerson <= n - 1
The problem asks to find all people who know a secret after a series of meetings. Initially, person 0 knows the secret and shares it with firstPerson
. During each meeting [x, y, time]
, if either x
or y
knows the secret, they share it with each other. Meetings happen instantaneously; sharing can occur within the same time frame. The solution should return a list of all people who eventually know the secret.
The most efficient approach uses a combination of sorting and Breadth-First Search (BFS).
Sort Meetings: Sort the meetings
array by time. This allows us to process meetings chronologically.
Iterate Through Time: Process meetings in chronological order. For meetings with the same time, process them together.
BFS for each time: For each set of meetings at the same time, construct a graph where nodes are people involved in those meetings and edges represent sharing the secret. Perform a BFS starting from those who already know the secret. Any person reachable during the BFS also learns the secret.
Update Knowledge: After processing each time, update the vis
array (or equivalent data structure), indicating which people know the secret.
Return Result: After processing all meetings, return a list of all indices i
where vis[i]
is true.
Overall Time Complexity: O(M log M + T(N + M)). In the worst case, T could be M, which makes the complexity O(M log M + M(N+M)). However, in most cases, T is considerably smaller than M.
vis
array: O(N)Overall Space Complexity: O(N + M)
The code implementations below reflect the explained approach. They utilize a vis
array to track which individuals know the secret, sorting the meetings by time, and then iterating through each unique time to apply a breadth-first search.
Python3:
from collections import defaultdict, deque
class Solution:
def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]:
vis = [False] * n
vis[0] = vis[firstPerson] = True
meetings.sort(key=lambda x: x[2])
i, m = 0, len(meetings)
while i < m:
j = i
while j + 1 < m and meetings[j + 1][2] == meetings[i][2]:
j += 1
s = set()
g = defaultdict(list)
for x, y, _ in meetings[i:j + 1]:
g[x].append(y)
g[y].append(x)
s.update([x, y])
q = deque([u for u in s if vis[u]])
while q:
u = q.popleft()
for v in g[u]:
if not vis[v]:
vis[v] = True
q.append(v)
i = j + 1
return [i for i, v in enumerate(vis) if v]
Java:
import java.util.*;
class Solution {
public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {
boolean[] vis = new boolean[n];
vis[0] = true;
vis[firstPerson] = true;
Arrays.sort(meetings, (a, b) -> a[2] - b[2]);
for (int i = 0; i < meetings.length;) {
int j = i;
while (j + 1 < meetings.length && meetings[j + 1][2] == meetings[i][2]) {
j++;
}
Map<Integer, List<Integer>> graph = new HashMap<>();
Set<Integer> nodes = new HashSet<>();
for (int k = i; k <= j; k++) {
int x = meetings[k][0], y = meetings[k][1];
graph.computeIfAbsent(x, k1 -> new ArrayList<>()).add(y);
graph.computeIfAbsent(y, k1 -> new ArrayList<>()).add(x);
nodes.add(x);
nodes.add(y);
}
Queue<Integer> q = new LinkedList<>();
for (int node : nodes) {
if (vis[node]) {
q.offer(node);
}
}
while (!q.isEmpty()) {
int u = q.poll();
for (int v : graph.getOrDefault(u, Collections.emptyList())) {
if (!vis[v]) {
vis[v] = true;
q.offer(v);
}
}
}
i = j + 1;
}
List<Integer> ans = new ArrayList<>();
for (int i = 0; i < n; i++) {
if (vis[i]) {
ans.add(i);
}
}
return ans;
}
}
The C++, Go, and TypeScript implementations would follow a similar structure, adapting the data structures to those languages' conventions. The core algorithm remains the same: sorting, iterative processing by time, and BFS for each time step.