Skip to content

Commit 6beb2b9

Browse files
authored
Merge branch 'master' into feature/max-product-subarray
2 parents 3963557 + bc94f21 commit 6beb2b9

File tree

4 files changed

+205
-0
lines changed

4 files changed

+205
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# 547. Number of Provinces
2+
3+
**Difficulty:** Medium
4+
**Category:** Graphs, DFS, Union Find
5+
**Leetcode Link:** [Problem Link](https://leetcode.com/problems/number-of-provinces/)
6+
7+
---
8+
9+
## 📝 Introduction
10+
11+
You are given an undirected graph represented as an adjacency matrix, where isConnected[i][j] = 1 indicates a direct connection between the ith and jth cities.
12+
A province is a group of directly or indirectly connected cities that are disconnected from other cities.
13+
The task is to count the number of such provinces in the graph.
14+
15+
Constraints:<br>
16+
- 1 ≤ n ≤ 200
17+
- isConnected[i][j] is 1 or 0
18+
- isConnected[i][i] is always 1
19+
20+
---
21+
22+
## 💡 Approach & Key Insights
23+
24+
The problem reduces to finding the number of connected components in an undirected graph.
25+
Each connected component represents one province.
26+
We can apply graph traversal techniques (DFS or BFS) to visit each connected component and count how many separate traversals we had to make.
27+
28+
---
29+
30+
## 🛠️ Breakdown of Approaches
31+
32+
### 1️⃣ Brute Force / Naive Approach
33+
34+
- **Explanation:**
35+
Treat each city as a node. For each city, initiate a DFS/BFS to mark all reachable cities.
36+
Use a visited array to avoid revisiting nodes. Every time we start a new DFS from an unvisited node, it indicates a new province.
37+
38+
- **Time Complexity:** O(N²) — because we scan the full adjacency matrix
39+
- **Space Complexity:** O(N) — for the visited array
40+
- **Example/Dry Run:**
41+
42+
```plaintext
43+
Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]]
44+
Step 1: Start DFS at node 0 → mark 0,1 as visited
45+
Step 2: Skip node 1 (already visited)
46+
Step 3: Node 2 is unvisited → new DFS → mark 2
47+
Provinces = 2
48+
```
49+
50+
---
51+
52+
### 2️⃣ Optimized Approach (DFS using adjacency list)
53+
54+
- **Explanation:**
55+
Convert the adjacency matrix to an adjacency list to reduce redundant checks.
56+
Perform DFS from each unvisited node, marking all nodes reachable from it.
57+
58+
- **Time Complexity:** O(V + E)
59+
- **Space Complexity:** O(V + E) for adjacency list + O(V) for visited array
60+
- **Example/Dry Run:**
61+
62+
```plaintext
63+
Input: [[1,0,0],[0,1,0],[0,0,1]]
64+
Adjacency List: [[], [], []] (self-loops ignored)
65+
Start DFS at node 0 → visit 0 → count++
66+
Start DFS at node 1 → visit 1 → count++
67+
Start DFS at node 2 → visit 2 → count++
68+
Output = 3 provinces
69+
```
70+
71+
---
72+
73+
### 3️⃣ Best / Final Optimized Approach (Union-Find)
74+
75+
- **Explanation:**
76+
Use Union-Find (Disjoint Set Union) to group connected cities.
77+
Initially, each city is its own parent. For every connection, perform a union operation.
78+
Finally, count how many unique parents exist.
79+
80+
- **Time Complexity:** O(N² × α(N)) — where α is the inverse Ackermann function
81+
- **Space Complexity:** O(N) — for parent array
82+
- **Example/Dry Run:**
83+
84+
```plaintext
85+
Input: [[1,1,0],[1,1,0],[0,0,1]]
86+
Parent: [0,1,2]
87+
Union(0,1) → Parent[1] = 0 → Parent: [0,0,2]
88+
Count unique parents → [0,2] → Output: 2
89+
```
90+
91+
---
92+
93+
## 📊 Complexity Analysis
94+
95+
| Approach | Time Complexity | Space Complexity |
96+
| ------------- | ------------------ | ---------------- |
97+
| Brute Force | O(N²) | O(N) |
98+
| DFS (Adj List)| O(V + E) | O(V + E) |
99+
| Union-Find | O(N² × α(N)) | O(N) |
100+
101+
---
102+
103+
## 📉 Optimization Ideas
104+
105+
- In the Union-Find approach, use both path compression and union by rank to optimize further.
106+
- Avoid converting to an adjacency list if the matrix is sparse.
107+
108+
---
109+
110+
## 📌 Example Walkthroughs & Dry Runs
111+
112+
```plaintext
113+
Example:
114+
Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]]
115+
Each city is isolated
116+
Result: 3 provinces
117+
118+
Example:
119+
Input: [[1,1,0],[1,1,0],[0,0,1]]
120+
City 0 and 1 are connected
121+
City 2 is isolated
122+
Result: 2 provinces
123+
```
124+
125+
---
126+
127+
## 🔗 Additional Resources
128+
129+
- [DFS Traversal - GFG](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/)
130+
- [Union Find Explained](https://www.geeksforgeeks.org/dsa/introduction-to-disjoint-set-data-structure-or-union-find-algorithm/)
131+
132+
---
133+
134+
Author: Abdul Wahab
135+
Date: 19/07/2025
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Solution {
2+
public:
3+
int findCircleNum(vector<vector<int>>& isConnected) {
4+
int n = isConnected.size();
5+
vector<bool> visited(n, false);
6+
int provinces = 0;
7+
8+
for (int i = 0; i < n; i++) {
9+
if (!visited[i]) {
10+
dfs(isConnected, visited, i);
11+
provinces++;
12+
}
13+
}
14+
15+
return provinces;
16+
}
17+
18+
private:
19+
void dfs(vector<vector<int>>& isConnected, vector<bool>& visited, int city) {
20+
visited[city] = true;
21+
for (int j = 0; j < isConnected.size(); j++) {
22+
if (isConnected[city][j] == 1 && !visited[j]) {
23+
dfs(isConnected, visited, j);
24+
}
25+
}
26+
}
27+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class Solution {
2+
public int findCircleNum(int[][] isConnected) {
3+
int n = isConnected.length;
4+
boolean[] visited = new boolean[n];
5+
int provinces = 0;
6+
7+
for (int i = 0; i < n; i++) {
8+
if (!visited[i]) {
9+
dfs(isConnected, visited, i);
10+
provinces++;
11+
}
12+
}
13+
14+
return provinces;
15+
}
16+
17+
private void dfs(int[][] isConnected, boolean[] visited, int city) {
18+
visited[city] = true;
19+
for (int j = 0; j < isConnected.length; j++) {
20+
if (isConnected[city][j] == 1 && !visited[j]) {
21+
dfs(isConnected, visited, j);
22+
}
23+
}
24+
}
25+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class Solution:
2+
def findCircleNum(self, isConnected: List[List[int]]) -> int:
3+
n = len(isConnected)
4+
visited = [False] * n
5+
provinces = 0
6+
7+
def dfs(city):
8+
visited[city] = True
9+
for j in range(n):
10+
if isConnected[city][j] == 1 and not visited[j]:
11+
dfs(j)
12+
13+
for i in range(n):
14+
if not visited[i]:
15+
dfs(i)
16+
provinces += 1
17+
18+
return provinces

0 commit comments

Comments
 (0)