Skip to content

Commit 826f6fe

Browse files
committed
Sync LeetCode submission Runtime - 599 ms (94.52%), Memory - 20.4 MB (27.85%)
1 parent 0f7eea1 commit 826f6fe

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<p>You are given a positive integer <code>n</code> representing the number of nodes in an <strong>undirected</strong> graph. The nodes are labeled from <code>1</code> to <code>n</code>.</p>
2+
3+
<p>You are also given a 2D integer array <code>edges</code>, where <code>edges[i] = [a<sub>i, </sub>b<sub>i</sub>]</code> indicates that there is a <strong>bidirectional</strong> edge between nodes <code>a<sub>i</sub></code> and <code>b<sub>i</sub></code>. <strong>Notice</strong> that the given graph may be disconnected.</p>
4+
5+
<p>Divide the nodes of the graph into <code>m</code> groups (<strong>1-indexed</strong>) such that:</p>
6+
7+
<ul>
8+
<li>Each node in the graph belongs to exactly one group.</li>
9+
<li>For every pair of nodes in the graph that are connected by an edge <code>[a<sub>i, </sub>b<sub>i</sub>]</code>, if <code>a<sub>i</sub></code> belongs to the group with index <code>x</code>, and <code>b<sub>i</sub></code> belongs to the group with index <code>y</code>, then <code>|y - x| = 1</code>.</li>
10+
</ul>
11+
12+
<p>Return <em>the maximum number of groups (i.e., maximum </em><code>m</code><em>) into which you can divide the nodes</em>. Return <code>-1</code> <em>if it is impossible to group the nodes with the given conditions</em>.</p>
13+
14+
<p>&nbsp;</p>
15+
<p><strong class="example">Example 1:</strong></p>
16+
<img alt="" src="https://assets.leetcode.com/uploads/2022/10/13/example1.png" style="width: 352px; height: 201px;" />
17+
<pre>
18+
<strong>Input:</strong> n = 6, edges = [[1,2],[1,4],[1,5],[2,6],[2,3],[4,6]]
19+
<strong>Output:</strong> 4
20+
<strong>Explanation:</strong> As shown in the image we:
21+
- Add node 5 to the first group.
22+
- Add node 1 to the second group.
23+
- Add nodes 2 and 4 to the third group.
24+
- Add nodes 3 and 6 to the fourth group.
25+
We can see that every edge is satisfied.
26+
It can be shown that that if we create a fifth group and move any node from the third or fourth group to it, at least on of the edges will not be satisfied.
27+
</pre>
28+
29+
<p><strong class="example">Example 2:</strong></p>
30+
31+
<pre>
32+
<strong>Input:</strong> n = 3, edges = [[1,2],[2,3],[3,1]]
33+
<strong>Output:</strong> -1
34+
<strong>Explanation:</strong> If we add node 1 to the first group, node 2 to the second group, and node 3 to the third group to satisfy the first two edges, we can see that the third edge will not be satisfied.
35+
It can be shown that no grouping is possible.
36+
</pre>
37+
38+
<p>&nbsp;</p>
39+
<p><strong>Constraints:</strong></p>
40+
41+
<ul>
42+
<li><code>1 &lt;= n &lt;= 500</code></li>
43+
<li><code>1 &lt;= edges.length &lt;= 10<sup>4</sup></code></li>
44+
<li><code>edges[i].length == 2</code></li>
45+
<li><code>1 &lt;= a<sub>i</sub>, b<sub>i</sub> &lt;= n</code></li>
46+
<li><code>a<sub>i</sub> != b<sub>i</sub></code></li>
47+
<li>There is at most one edge between any pair of vertices.</li>
48+
</ul>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Approach 1: Graph Coloring + Longest Shortest Path
2+
3+
# n = no. of nodes in graph, m = len(edges)
4+
# Time: O(n * (n + m))
5+
# Space: O(n)
6+
7+
from collections import deque
8+
9+
class Solution:
10+
def magnificentSets(self, n: int, edges: List[List[int]]) -> int:
11+
adj_list = [[] for _ in range(n)]
12+
13+
for edge in edges:
14+
adj_list[edge[0] - 1].append(edge[1] - 1)
15+
adj_list[edge[1] - 1].append(edge[0] - 1)
16+
17+
colors = [-1] * n
18+
19+
# Check if the graph is bipartite
20+
for node in range(n):
21+
if colors[node] != -1:
22+
continue
23+
# Start coloring from uncolored nodes
24+
colors[node] = 0
25+
if not self._is_bipartite(adj_list, node, colors):
26+
return -1
27+
28+
# Calculate the longest shortest path for each node
29+
distances = [
30+
self._get_longest_shortest_path(adj_list, node, n)
31+
for node in range(n)
32+
]
33+
34+
# Calculate the total maximum number of groups across all components
35+
max_number_of_groups = 0
36+
visited = [False] * n
37+
38+
for node in range(n):
39+
if visited[node]:
40+
continue
41+
# Add the number of groups for this component to the total
42+
max_number_of_groups += self._get_number_of_groups_for_component(adj_list, node, distances, visited)
43+
44+
return max_number_of_groups
45+
46+
# Checks if the graph is bipartite starting from the given node
47+
def _is_bipartite(self, adj_list, node, colors):
48+
for neighbor in adj_list[node]:
49+
50+
# If the neighbor has the same color, the graph is not bipartite
51+
if colors[neighbor] == colors[node]:
52+
return False
53+
54+
# If the neighbor is already colored, skip it
55+
if colors[neighbor] != -1:
56+
continue
57+
58+
# Assign the opposite color to the neighbor
59+
colors[neighbor] = (colors[node] + 1) % 2
60+
61+
# Recursively check bipartiteness for the neighbor; return False if its fails
62+
if not self._is_bipartite(adj_list, neighbor, colors):
63+
return False
64+
65+
# If all neighbors are properly colored, return True
66+
return True
67+
68+
# Computes the longest shortest path (height) in the graph starting from the source node
69+
def _get_longest_shortest_path(self, adj_list, src_node, n):
70+
nodes_queue = deque([src_node])
71+
visited = [False] * n
72+
visited[src_node] = True
73+
distance = 0
74+
75+
# Perform BFS layer by layer
76+
while nodes_queue:
77+
# Process all nodes in the current layer
78+
for _ in range(len(nodes_queue)):
79+
current_node = nodes_queue.popleft()
80+
81+
# Visit all unvisited neighbors of the current node
82+
for neighbor in adj_list[current_node]:
83+
if visited[neighbor]:
84+
continue
85+
visited[neighbor] = True
86+
nodes_queue.append(neighbor)
87+
88+
# Increment the distance for each layer
89+
distance += 1
90+
91+
return distance
92+
93+
# Calculates the max number of groups for a connected component
94+
def _get_number_of_groups_for_component(self, adj_list, node, distances, visited):
95+
# Start with the distance of the current node as maximum
96+
max_number_of_groups = distances[node]
97+
visited[node] = True
98+
99+
# Recursively calculate the maximum for all unvisited neighbors
100+
for neighbor in adj_list[node]:
101+
if visited[neighbor]:
102+
continue
103+
max_number_of_groups = max(
104+
max_number_of_groups,
105+
self._get_number_of_groups_for_component(
106+
adj_list, neighbor, distances, visited
107+
)
108+
)
109+
110+
return max_number_of_groups
111+
112+

0 commit comments

Comments
 (0)