n people in a social group
input array logs where logs[i] = [timestamp, x, y]x and y will become friends at timestmap
friendship is symmetric (undirected)
friendship = direct connection
acquaintance = 1 degree of separation
return the earliest time for which every person became acquainted with every other person
return -1 if not possible
πWhat Were My Initial Thoughts?
- we can convert this into a graph problem
- convert logs into an adjacency list
- we meed to track when all nodes (people) are connected in one component
- this is essentially a connected components problem, which we can solve with:
- Prims Minimum Spanning Tree Algorithm
- Union Find
π‘ Explanation of Solution
Union Find:
1. Sort logs by timestamp
- since friendships happen at different timestamps, processing them in order ensures correctness
2. use union-find DSU
- maintain a parent array where parent[i] points to the representative root of the set containing i
- a rank array is used for optimization (union by rank)
- each time two people become friends (union(x,y)), we reduce the number of disjoint sets (connected components)
- when the number of components reach 1, it means everyone is connected
3. return the earliest timestamp when all people are connected
Prims Algorithm:
1. model the friendships as an undirected weighted graph
- each person is a node
- each friendship (x,y,timestamp) is an edge where the weight is the timestamp
2. use prim's algorithm to build a minimum spanning tree (MST)
- start from any node (0 or any arbitrary person)
- use a min-heap (priority-queue) to always pick the smallest timestamp edge that expands the connected component
- when all n nodes are connected, return the maximum edge weight used so far
- (the earliest timestamp where everyone became connected)
β Complexity Analysis
Union Find:
- Time Complexity: O(m log m)
- sorting operation
- union find operations are O(Ξ±(n)) (inverse ackerman function) which is nearly constant
- Space Complexity: O(m * n)
Prims MST
- Time Complexity: O(m log n)
- where n is the number of nodes (people)
- m is the number of edges (friendships in logs)
- Space Complexity: O(m * n)
π» Implementation of Solution
Union Find
class UnionFind {private: vector<int> parent, rank; int components; // Number of disjoint setspublic: UnionFind(int n) { parent.resize(n); rank.resize(n, 1); components = n; // Initially, everyone is in their own group for (int i = 0; i < n; i++) { parent[i] = i; // Everyone is their own leader } } int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); // Path compression } return parent[x]; } bool unionSet(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { // Union by rank if (rank[rootX] > rank[rootY]) { parent[rootY] = rootX; } else if (rank[rootX] < rank[rootY]) { parent[rootX] = rootY; } else { parent[rootY] = rootX; rank[rootX]++; } components--; // Reduce the number of components return true; } return false; // Already in the same component } bool isConnected() { return components == 1; // If all people are in one set }};class Solution {public: int earliestAcq(vector<vector<int>>& logs, int n) { sort(logs.begin(), logs.end()); // Sort logs by timestamp UnionFind uf(n); for (auto& log : logs) { int timestamp = log[0], x = log[1], y = log[2]; uf.unionSet(x, y); if (uf.isConnected()) { return timestamp; // Earliest time when everyone is connected } } return -1; // If we never reach a single component }};
Primβs Algorithm (MST)
class Solution {public: int earliestAcq(vector<vector<int>>& logs, int n) { // Step 1: Sort logs by timestamp (ensures we process edges in order) sort(logs.begin(), logs.end()); // Step 2: Build an adjacency list graph unordered_map<int, vector<pair<int, int>>> graph; for (auto& log : logs) { int timestamp = log[0], x = log[1], y = log[2]; graph[x].push_back({y, timestamp}); graph[y].push_back({x, timestamp}); } // Step 3: Use Prim's algorithm to construct MST priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; // Min-Heap (timestamp, node) unordered_set<int> visited; // Start from any node (e.g., 0) pq.push({0, 0}); // (timestamp, node) int maxTimestamp = 0; while (!pq.empty()) { auto [timestamp, node] = pq.top(); pq.pop(); if (visited.count(node)) continue; visited.insert(node); maxTimestamp = max(maxTimestamp, timestamp); // Track latest timestamp used // Add neighbors to the queue for (auto& [neighbor, edgeTime] : graph[node]) { if (!visited.count(neighbor)) { pq.push({edgeTime, neighbor}); } } // If all nodes are connected, return max timestamp used if (visited.size() == n) return maxTimestamp; } return -1; // If we couldn't connect all nodes }};