You are given an integer n. There is an undirected graph with n nodes, numbered from 0 to n - 1. You are given a 2D integer array edges where edges[i] = [ai, bi] denotes that there exists an undirected edge connecting nodes ai and bi.
Return the number of pairs of different nodes that are unreachable from each other.
Example 1:
Input: n = 3, edges = [[0,1],[0,2],[1,2]] Output: 0 Explanation: There are no pairs of nodes that are unreachable from each other. Therefore, we return 0.
Example 2:
Input: n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]] Output: 14 Explanation: There are 14 pairs of nodes that are unreachable from each other: [[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]]. Therefore, we return 14.
Constraints:
1 <= n <= 1050 <= edges.length <= 2 * 105edges[i].length == 20 <= ai, bi < nai != biWhen you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The core idea is to check every possible pair of nodes in the graph. For each pair, we'll figure out if there's a path connecting them, and if there isn't, we'll count that pair as unreachable.
Here's how the algorithm would work step-by-step:
def count_unreachable_pairs(number_of_nodes, edges):
graph = [[] for _ in range(number_of_nodes)]
for node1, node2 in edges:
graph[node1].append(node2)
graph[node2].append(node1)
unreachable_pairs_count = 0
for first_node in range(number_of_nodes):
for second_node in range(first_node + 1, number_of_nodes):
# We start a breadth first search to find a path
visited = [False] * number_of_nodes
queue = [first_node]
visited[first_node] = True
while queue:
current_node = queue.pop(0)
if current_node == second_node:
break
for neighbor in graph[current_node]:
if not visited[neighbor]:
queue.append(neighbor)
visited[neighbor] = True
# If a path was not found, increment the counter
if not visited[second_node]:
unreachable_pairs_count += 1
return unreachable_pairs_countThe problem asks to count pairs of nodes that cannot reach each other in a graph. The key idea is to find groups of connected nodes and use the sizes of these groups to figure out unreachable pairs more efficiently than checking all pairs individually.
Here's how the algorithm would work step-by-step:
def count_unreachable_pairs(number_of_nodes, edges):
graph = [[] for _ in range(number_of_nodes)]
for node_a, node_b in edges:
graph[node_a].append(node_b)
graph[node_b].append(node_a)
visited = [False] * number_of_nodes
components = []
def depth_first_search(node, current_component):
visited[node] = True
current_component.append(node)
for neighbor in graph[node]:
if not visited[neighbor]:
depth_first_search(neighbor, current_component)
# Find all connected components
for node in range(number_of_nodes):
if not visited[node]:
current_component = []
depth_first_search(node, current_component)
components.append(current_component)
component_sizes = [len(component) for component in components]
total_unreachable_pairs = 0
# Iterate through the sizes of connected components
for component_size in component_sizes:
# Count nodes not reachable from the current component.
unreachable_nodes = number_of_nodes - component_size
total_unreachable_pairs += component_size * unreachable_nodes
# Each pair was counted twice so divide by 2
return total_unreachable_pairs // 2| Case | How to Handle |
|---|---|
| Empty graph (n = 0) | Return 0, as there are no nodes and thus no pairs. |
| Single node graph (n = 1) | Return 0, as there are no pairs of nodes. |
| Graph with no edges | Each node is its own connected component; the answer is n * (n - 1) / 2. |
| Fully connected graph | Return 0, as all nodes are reachable from each other. |
| Graph with a single connected component | Return 0, as all nodes are reachable from each other. |
| Large graph (n close to limit) to check for integer overflow in calculations | Use 64-bit integers (long) to store the number of nodes in each component and the total count of unreachable pairs. |
| Graph with many small connected components | Ensure the algorithm efficiently iterates through all components and correctly calculates the unreachable pairs for each combination. |
| Disjoint graph with one very large component, and many very small components | Ensure the algorithm doesn't time out calculating the large component's size using an efficient graph traversal method like Depth-First Search (DFS) or Breadth-First Search (BFS). |