Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
The Earliest Moment When Everyone Become Friends in C++
The problem asks us to find the earliest moment when everyone in a social group becomes acquainted with everyone else. This is a classic Union-Find (Disjoint Set Union) problem where we need to track connected components and determine when all people form a single connected group.
Given N people with IDs from 0 to N-1 and a list of friendship logs, each log contains [timestamp, person_A, person_B]. We need to find the earliest timestamp when all people are connected through friendships.
Algorithm Overview
We use the Union-Find data structure with the following approach ?
Sort logs by timestamp to process events chronologically
Use Union-Find to track connected components
After each union operation, check if all people are in one component
Return the timestamp when this happens, or -1 if it never occurs
Python Implementation
Method 1: Using Union-Find with Path Compression
def earliest_acq(logs, n):
# Initialize parent array for Union-Find
parent = list(range(n))
def find(x):
if parent[x] != x:
parent[x] = find(parent[x]) # Path compression
return parent[x]
def union(x, y):
root_x = find(x)
root_y = find(y)
if root_x != root_y:
parent[root_x] = root_y
return True # Successfully merged two components
return False # Already in same component
# Sort logs by timestamp
logs.sort()
components = n # Initially n separate components
for timestamp, person_a, person_b in logs:
if union(person_a, person_b):
components -= 1
if components == 1: # All people are connected
return timestamp
return -1 # Not everyone is connected
# Test the function
logs = [[20190101,0,1],[20190104,3,4],[20190107,2,3],[20190211,1,5],
[20190224,2,4],[20190301,0,3],[20190312,1,2],[20190322,4,5]]
n = 6
result = earliest_acq(logs, n)
print(f"Earliest moment when everyone becomes friends: {result}")
Earliest moment when everyone becomes friends: 20190301
Step-by-Step Execution
Let's trace through the example to understand how the algorithm works ?
def earliest_acq_with_trace(logs, n):
parent = list(range(n))
def find(x):
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(x, y):
root_x = find(x)
root_y = find(y)
if root_x != root_y:
parent[root_x] = root_y
return True
return False
def get_components():
groups = {}
for i in range(n):
root = find(i)
if root not in groups:
groups[root] = []
groups[root].append(i)
return list(groups.values())
logs.sort()
components = n
print(f"Initial components: {get_components()}")
for timestamp, person_a, person_b in logs:
if union(person_a, person_b):
components -= 1
print(f"Timestamp {timestamp}: Connected {person_a} and {person_b}")
print(f"Current components: {get_components()}")
if components == 1:
return timestamp
else:
print(f"Timestamp {timestamp}: {person_a} and {person_b} already connected")
return -1
# Test with trace
logs = [[20190101,0,1],[20190104,3,4],[20190107,2,3],[20190211,1,5],
[20190224,2,4],[20190301,0,3],[20190312,1,2],[20190322,4,5]]
n = 6
result = earliest_acq_with_trace(logs, n)
print(f"\nFinal result: {result}")
Initial components: [[0], [1], [2], [3], [4], [5]] Timestamp 20190101: Connected 0 and 1 Current components: [[2], [3], [4], [5], [0, 1]] Timestamp 20190104: Connected 3 and 4 Current components: [[2], [5], [0, 1], [3, 4]] Timestamp 20190107: Connected 2 and 3 Current components: [[5], [0, 1], [2, 3, 4]] Timestamp 20190211: Connected 1 and 5 Current components: [[0, 1, 5], [2, 3, 4]] Timestamp 20190224: 2 and 4 already connected Timestamp 20190301: Connected 0 and 3 Current components: [[0, 1, 5, 2, 3, 4]] Final result: 20190301
Time and Space Complexity
| Aspect | Complexity | Explanation |
|---|---|---|
| Time | O(M log M + M ?(N)) | M logs sorting + M union operations |
| Space | O(N) | Parent array for Union-Find |
Where M is the number of logs, N is the number of people, and ? is the inverse Ackermann function (practically constant).
Key Points
Path Compression: Optimizes find operations by flattening the tree structure
Component Counting: Track the number of separate components to detect when all are connected
Early Termination: Return immediately when components count reaches 1
Sorting: Process events chronologically to find the earliest moment
Conclusion
The Union-Find data structure efficiently solves this connectivity problem by tracking connected components and detecting when all people form a single group. The algorithm processes friendship events chronologically and returns the earliest timestamp when everyone becomes acquainted.
---