[LeetCode] 547. Friend Circles
There are n
cities. Some of them are connected, while some are not. If city a
is connected directly with city b
, and city b
is connected directly with city c
, then city a
is connected indirectly with city c
.
A province is a group of directly or indirectly connected cities and no other cities outside of the group.
You are given an n x n
matrix isConnected
where isConnected[i][j] = 1
if the ith
city and the jth
city are directly connected, and isConnected[i][j] = 0
otherwise.
Return the total number of provinces.
Example 1:
Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]] Output: 2
Example 2:
Input: 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]
is1
or0
.isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
省份数量。
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-provinces
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这是一道典型的 union find 的题目,找图里面有多少个连通分量。我这里给出两种解法,一种 DFS 的解法,一种 union find 的解法。
DFS做法的思路是创建一个长度为 n 的数组,记录每个人是否被访问过,如果某个人没有被访问过,则对其做 DFS 遍历,同时 count++,因为即使这个人没有朋友,他也可以自成一个朋友圈。DFS 递归调用的时候,判断当前的人 i 和其他所有人的关系,并且记得每当遍历过一个人的时候,先把他标记成访问过,否则会 stack overflow。
时间O(n^2)
空间O(n)
Java实现
1 class Solution { 2 int n; 3 4 public int findCircleNum(int[][] isConnected) { 5 n = isConnected.length; 6 boolean[] visited = new boolean[n]; 7 int count = 0; 8 for (int i = 0; i < n; i++) { 9 if (!visited[i]) { 10 dfs(isConnected, visited, i); 11 count++; 12 } 13 } 14 return count; 15 } 16 17 private void dfs(int[][] isConnected, boolean[] visited, int i) { 18 for (int j = 0; j < n; j++) { 19 if (i == j) { 20 continue; 21 } 22 if (!visited[j] && isConnected[i][j] == 1) { 23 visited[j] = true; 24 dfs(isConnected, visited, j); 25 } 26 } 27 } 28 }
Union Find的做法需要依赖一个class。我这里同时提供两个帖子,一个有并查集的图解,一个有并查集的代码模板。代码中rank的意思是每个联通分量的大小,如果两个集合是联通的,我们尽量把小的放进大的里面。
时间O(V * E)
空间O(n)
Java实现
1 class Solution { 2 class UnionFind { 3 // rank[i]表示以i为根节点的树的高度 4 private int[] parent, rank; 5 private int count; 6 7 public UnionFind(int n) { 8 parent = new int[n]; 9 rank = new int[n]; 10 count = n; 11 for (int i = 0; i < n; i++) { 12 parent[i] = i; 13 rank[i] = 1; 14 } 15 } 16 17 public int find(int p) { 18 // path compression 19 // 当前节点遍历时将节点指向父亲的父亲节点 20 while (p != parent[p]) { 21 parent[p] = parent[parent[p]]; 22 p = parent[p]; 23 } 24 return p; 25 } 26 27 public void union(int p, int q) { 28 int rootP = find(p); 29 int rootQ = find(q); 30 if (rootP == rootQ) { 31 return; 32 } 33 // 这里合并的时候判断树的高度,将其高度低的节点指向高度高的根节点 34 if (rank[rootP] > rank[rootQ]) { 35 parent[rootQ] = rootP; 36 rank[rootP] += rank[rootQ]; 37 } else { 38 parent[rootP] = rootQ; 39 rank[rootQ] += rank[rootP]; 40 } 41 count--; 42 } 43 44 public int count() { 45 return count; 46 } 47 } 48 49 public int findCircleNum(int[][] isConnected) { 50 int n = isConnected.length; 51 UnionFind uf = new UnionFind(n); 52 for (int i = 0; i < n; i++) { 53 for (int j = i + 1; j < n; j++) { 54 if (isConnected[i][j] == 1) { 55 uf.union(i, j); 56 } 57 } 58 } 59 return uf.count(); 60 } 61 }
相关题目