diff --git a/src/class09_15/Code01_FriendCircles.java b/src/class09_15/Code01_FriendCircles.java index 4e83a8e..5f2ad67 100644 --- a/src/class09_15/Code01_FriendCircles.java +++ b/src/class09_15/Code01_FriendCircles.java @@ -7,10 +7,11 @@ public class Code01_FriendCircles { public static int findCircleNum(int[][] M) { int N = M.length; + // {0} {1} {2} {N-1} UnionFind unionFind = new UnionFind(N); for (int i = 0; i < N; i++) { for (int j = i + 1; j < N; j++) { - if (M[i][j] == 1) { + if (M[i][j] == 1) { // i和j互相认识 unionFind.union(i, j); } } @@ -19,9 +20,14 @@ public class Code01_FriendCircles { } public static class UnionFind { + // parent[i] = k : i的父亲是k private int[] parent; + // size[i] = k : 如果i是代表节点,size[i]才有意义,否则无意义 + // i所在的集合大小是多少 private int[] size; + // 辅助结构 private int[] help; + // 一共有多少个集合 private int sets; public UnionFind(int N) { @@ -35,6 +41,8 @@ public class Code01_FriendCircles { } } + // 从i开始一直往上,往上到不能再往上,代表节点,返回 + // 这个过程要做路径压缩 private int find(int i) { int hi = 0; while (i != parent[i]) { diff --git a/src/class09_15/Code02_NumberOfIslands.java b/src/class09_15/Code02_NumberOfIslands.java index df8d8df..e27a9ea 100644 --- a/src/class09_15/Code02_NumberOfIslands.java +++ b/src/class09_15/Code02_NumberOfIslands.java @@ -23,6 +23,7 @@ public class Code02_NumberOfIslands { return islands; } + // 从(i,j)这个位置出发,把所有练成一片的'1'字符,变成0 public static void infect(char[][] board, int i, int j) { if (i < 0 || i == board.length || j < 0 || j == board[0].length || board[i][j] != '1') { return; @@ -49,6 +50,7 @@ public class Code02_NumberOfIslands { } UnionFind1 uf = new UnionFind1<>(dotList); for (int j = 1; j < col; j++) { + // (0,j) (0,0)跳过了 (0,1) (0,2) (0,3) if (board[0][j - 1] == '1' && board[0][j] == '1') { uf.union(dots[0][j - 1], dots[0][j]); } @@ -192,10 +194,12 @@ public class Code02_NumberOfIslands { } } + // (r,c) -> i private int index(int r, int c) { return r * col + c; } + // 原始位置 -> 下标 private int find(int i) { int hi = 0; while (i != parent[i]) { diff --git a/src/class09_15/Code03_NumberOfIslandsII.java b/src/class09_15/Code03_NumberOfIslandsII.java index 057d96b..409fa3a 100644 --- a/src/class09_15/Code03_NumberOfIslandsII.java +++ b/src/class09_15/Code03_NumberOfIslandsII.java @@ -1,6 +1,7 @@ package class09_15; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; // 本题为leetcode原题 @@ -8,8 +9,8 @@ import java.util.List; // 所有方法都可以直接通过 public class Code03_NumberOfIslandsII { - public static List numIslands2(int m, int n, int[][] positions) { - UnionFind uf = new UnionFind(m, n); + public static List numIslands21(int m, int n, int[][] positions) { + UnionFind1 uf = new UnionFind1(m, n); List ans = new ArrayList<>(); for (int[] position : positions) { ans.add(uf.connect(position[0], position[1])); @@ -17,7 +18,7 @@ public class Code03_NumberOfIslandsII { return ans; } - public static class UnionFind { + public static class UnionFind1 { private int[] parent; private int[] size; private int[] help; @@ -25,7 +26,7 @@ public class Code03_NumberOfIslandsII { private final int col; private int sets; - public UnionFind(int m, int n) { + public UnionFind1(int m, int n) { row = m; col = n; sets = 0; @@ -74,16 +75,87 @@ public class Code03_NumberOfIslandsII { } } - public int connect(int i, int j) { - int index = index(i, j); + public int connect(int r, int c) { + int index = index(r, c); if (size[index] == 0) { parent[index] = index; size[index] = 1; sets++; - union(i - 1, j, i, j); - union(i + 1, j, i, j); - union(i, j - 1, i, j); - union(i, j + 1, i, j); + union(r - 1, c, r, c); + union(r + 1, c, r, c); + union(r, c - 1, r, c); + union(r, c + 1, r, c); + } + return sets; + } + + } + + // 课上讲的如果m*n比较大,会经历很重的初始化,而k比较小,怎么优化的方法 + public static List numIslands22(int m, int n, int[][] positions) { + UnionFind2 uf = new UnionFind2(); + List ans = new ArrayList<>(); + for (int[] position : positions) { + ans.add(uf.connect(position[0], position[1])); + } + return ans; + } + + public static class UnionFind2 { + private HashMap parent; + private HashMap size; + private ArrayList help; + private int sets; + + public UnionFind2() { + parent = new HashMap<>(); + size = new HashMap<>(); + help = new ArrayList<>(); + sets = 0; + } + + private String find(String cur) { + while (!cur.equals(parent.get(cur))) { + help.add(cur); + cur = parent.get(cur); + } + for (String str : help) { + parent.put(str, cur); + } + help.clear(); + return cur; + } + + private void union(String s1, String s2) { + if (parent.containsKey(s1) && parent.containsKey(s2)) { + String f1 = find(s1); + String f2 = find(s2); + if (!f1.equals(f2)) { + int size1 = size.get(f1); + int size2 = size.get(f2); + String big = size1 >= size2 ? f1 : f2; + String small = big == f1 ? f2 : f1; + parent.put(small, big); + size.put(big, size1 + size2); + sets--; + } + } + } + + public int connect(int r, int c) { + String key = String.valueOf(r) + "_" + String.valueOf(c); + if (!parent.containsKey(key)) { + parent.put(key, key); + size.put(key, 1); + sets++; + String up = String.valueOf(r - 1) + "_" + String.valueOf(c); + String down = String.valueOf(r + 1) + "_" + String.valueOf(c); + String left = String.valueOf(r) + "_" + String.valueOf(c - 1); + String right = String.valueOf(r) + "_" + String.valueOf(c + 1); + union(up, key); + union(down, key); + union(left, key); + union(right, key); } return sets; }