{x}
blog image

Find All People With Secret

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

Problem Description

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.

Approach

The most efficient approach uses a combination of sorting and Breadth-First Search (BFS).

  1. Sort Meetings: Sort the meetings array by time. This allows us to process meetings chronologically.

  2. Iterate Through Time: Process meetings in chronological order. For meetings with the same time, process them together.

  3. 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.

  4. Update Knowledge: After processing each time, update the vis array (or equivalent data structure), indicating which people know the secret.

  5. Return Result: After processing all meetings, return a list of all indices i where vis[i] is true.

Time Complexity Analysis

  • Sorting meetings: O(M log M), where M is the number of meetings.
  • Iterating through meetings: O(M).
  • BFS for each time: In the worst case, all people could be involved in meetings at the same time, resulting in a BFS on a graph with up to N nodes and M edges (worst case when every pair of people meets at the same time). BFS is O(V + E), where V is the number of vertices and E is the number of edges; therefore, the BFS is O(N + M) in the worst case. Since we repeat BFS for each unique time, the total time for BFS would be O(T(N+M)), where T is the number of unique times.

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.

Space Complexity Analysis

  • vis array: O(N)
  • Graph (adjacency list): O(M) in the worst case (all meetings at the same time)
  • Queue for BFS: O(N) in the worst case.

Overall Space Complexity: O(N + M)

Code Implementations

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.