πŸ“ Problem Details

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 sets
public:
    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
    }
};