|
| 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 |
0 commit comments