1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class Solution { private int[] cityParent; private int[] rank;
private void initialize() { for (int i = 1; i < cityParent.length; i++) { cityParent[i] = i; rank[i] = 1; } }
private int find(int city) { if (city == cityParent[city]) { return city; } return cityParent[city] = find(cityParent[city]); }
private void union(int city1, int city2) { int city1Root = find(city1); int city2Root = find(city2); if (city1Root != city2Root) { if (rank[city1Root] < rank[city2Root]) { cityParent[city1Root] = city2Root; } else if (rank[city1Root] > rank[city2Root]) { cityParent[city2Root] = city1Root; } else { cityParent[city2Root] = city1Root; rank[city1Root] += 1; } } }
public int findCircleNum(int[][] isConnected) { int numOfCities = isConnected.length; cityParent = new int[numOfCities + 1]; rank = new int[numOfCities + 1]; initialize(); for (int i = 0; i < isConnected.length; i++) { for (int j = 0; j < isConnected[0].length; j++) { if (isConnected[i][j] == 1) { union(i + 1, j + 1); } } } Set<Integer> rootCities = new HashSet<>(); for (int i = 1; i <= numOfCities; i++) { rootCities.add(find(i)); } return rootCities.size(); } }
|
Union Find. 我的首次尝试. 非常好用.
时间复杂度: O(n^2)
空间复杂度: O(n^2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| class Solution { public int findCircleNum(int[][] isConnected) { if (isConnected == null || isConnected.length == 0) { return 0; }
int n = isConnected.length; UnionFind uf = new UnionFind(n); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (isConnected[i][j] == 1) { uf.union(i, j); } } }
return uf.getCount(); }
class UnionFind { private int[] root; private int[] rank; private int count;
UnionFind(int size) { root = new int[size]; rank = new int[size]; count = size; for (int i = 0; i < size; i++) { root[i] = i; rank[i] = 1; } }
int find(int x) { if (x == root[x]) { return x; } return root[x] = find(root[x]); }
void union(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { if (rank[rootX] > rank[rootY]) { root[rootY] = rootX; } else if (rank[rootX] < rank[rootY]) { root[rootX] = rootY; } else { root[rootY] = rootX; rank[rootX] += 1; } count--; } }
int getCount() { return count; } } }
|
这是官方的题解. 用一个inner class来表示union find. 这个class里面还记录了一个count变量, 它一开始被初始化为city的个数. 当出现成功的union后, 我们让count减1. 这个做法学到了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| class Solution { private static class UnionFind { private int[] cityParent; private int[] rank; private int count;
private UnionFind(int size) { cityParent = new int[size + 1]; rank = new int[size + 1]; for (int i = 1; i < cityParent.length; i++) { cityParent[i] = i; rank[i] = 1; } count = size; }
private int find(int city) { if (city == cityParent[city]) { return city; } return cityParent[city] = find(cityParent[city]); }
private void union(int city1, int city2) { int city1Root = find(city1); int city2Root = find(city2); if (city1Root != city2Root) { if (rank[city1Root] < rank[city2Root]) { cityParent[city1Root] = city2Root; } else if (rank[city1Root] > rank[city2Root]) { cityParent[city2Root] = city1Root; } else { cityParent[city2Root] = city1Root; rank[city1Root] += 1; } count -= 1; } }
private int getCount() { return count; } }
public int findCircleNum(int[][] isConnected) { int numOfCities = isConnected.length; UnionFind uf = new UnionFind(numOfCities); for (int i = 0; i < isConnected.length; i++) { for (int j = 0; j < isConnected[0].length; j++) { if (isConnected[i][j] == 1) { uf.union(i + 1, j + 1); } } } return uf.getCount(); } }
|
这个是我自己又把union find打包成class重写了一遍. 这就是模板.