You are given an n x n
matrix isConnected
where isConnected[i][j] = 1
if the i^th
city and the j^th
city are directly connected, and isConnected[i][j] = 0
otherwise.
A province is a group of directly or indirectly connected cities and no other cities outside of the group.
Write a function to return the total number of provinces.
Example 1:
isConnected = [[1,1,0],[1,1,0],[0,0,1]]
Output: 2
Example 2:
isConnected = [[1,0,0],[0,1,0],[0,0,1]]
Output: 3
Constraints:
1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j]
is 1
or 0
.isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
When 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:
Think of each city as a person and a connection as friendship. The brute force approach explores how many separate groups of friends (provinces) there are by directly examining every possible friendship between cities.
Here's how the algorithm would work step-by-step:
def find_number_of_provinces(adjacency_matrix):
number_of_cities = len(adjacency_matrix)
visited = [False] * number_of_cities
number_of_provinces = 0
def depth_first_search(city_index):
visited[city_index] = True
# Explore all connected cities using DFS
for neighbor_index in range(number_of_cities):
if adjacency_matrix[city_index][neighbor_index] == 1 and not visited[neighbor_index]:
# Recursively visit unvisited neighbors
depth_first_search(neighbor_index)
for city_index in range(number_of_cities):
# Start DFS if city not visited yet
if not visited[city_index]:
# Increment province count on new component
number_of_provinces += 1
depth_first_search(city_index)
return number_of_provinces
The problem involves finding groups of connected cities, where a connection means there's a direct road between them. The most efficient way to do this is to explore each city and its connections, marking all connected cities as part of the same group until no more connections are found.
Here's how the algorithm would work step-by-step:
def find_number_of_provinces(adjacency_matrix):
number_of_cities = len(adjacency_matrix)
visited_cities = [False] * number_of_cities
number_of_provinces = 0
def depth_first_search(city_index):
visited_cities[city_index] = True
for neighbor_index in range(number_of_cities):
if adjacency_matrix[city_index][neighbor_index] == 1 and not visited_cities[neighbor_index]:
depth_first_search(neighbor_index)
for city_index in range(number_of_cities):
# Start a new DFS if the city hasn't been visited.
if not visited_cities[city_index]:
depth_first_search(city_index)
# Increment province count after exploring all connected cities.
number_of_provinces += 1
return number_of_provinces
Case | How to Handle |
---|---|
Null or empty input adjacency matrix | Return 0 if the matrix is null or empty since there are no cities or provinces. |
Adjacency matrix is not square (n x n) | Throw an IllegalArgumentException or return an error code since a non-square matrix is invalid for representing city connections. |
Single city (n=1) | Return 1, as a single city always forms its own province. |
All cities are disconnected (all values are 0 except the diagonal) | Return n (number of cities) since each city forms its own province. |
All cities are connected (all values are 1) | Return 1, since all cities form a single province. |
Large number of cities (scalability) | Use a Disjoint Set Union (DSU) or Depth-First Search (DFS) algorithm, which can handle large inputs efficiently in O(n) or O(n^2) time respectively. |
Input matrix contains values other than 0 or 1 | Treat any non-zero value as a connection (1) or throw an exception since the problem usually defines 0 and 1 to represent connectedness. |
Integer overflow in the number of provinces (highly unlikely but theoretically possible with extremely large n) | The number of provinces will always be less than or equal to n, so integer overflow is not expected given reasonable input size, but one could check for it in extremely high use cases. |