diff --git a/src/class09_15/Code01_FriendCircles.java b/src/class09_15/Code01_FriendCircles.java new file mode 100644 index 0000000..398d911 --- /dev/null +++ b/src/class09_15/Code01_FriendCircles.java @@ -0,0 +1,69 @@ +package class09_15; + +// 本题为leetcode原题 +// 测试链接:https://leetcode.com/problems/friend-circles/ +// 可以直接通过 +public class Code01_FriendCircles { + + public static class UnionFind { + private int[] parent; + private int[] size; + private int[] help; + private int sets; + + public UnionFind(int N) { + parent = new int[N]; + size = new int[N]; + help = new int[N]; + sets = N; + for (int i = 0; i < N; i++) { + parent[i] = i; + size[i] = 1; + } + } + + private int find(int i) { + int hi = 0; + while (i != parent[i]) { + help[hi++] = i; + i = parent[i]; + } + for (hi--; hi >= 0; hi--) { + parent[help[hi]] = i; + } + return i; + } + + public void union(int i, int j) { + int f1 = find(i); + int f2 = find(j); + if (f1 != f2) { + if (size[f1] >= size[f2]) { + size[f1] += size[f2]; + parent[f2] = f1; + } else { + size[f2] += size[f1]; + parent[f1] = f2; + } + sets--; + } + } + + public int sets() { + return sets; + } + } + + public static int findCircleNum(int[][] M) { + int N = M.length; + 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) { + unionFind.union(i, j); + } + } + } + return unionFind.sets(); + } +} diff --git a/src/class09_14/Code06_IslandProblem.java b/src/class09_15/Code02_NumberOfIslands.java similarity index 57% rename from src/class09_14/Code06_IslandProblem.java rename to src/class09_15/Code02_NumberOfIslands.java index fa9c10d..5ffdc55 100644 --- a/src/class09_14/Code06_IslandProblem.java +++ b/src/class09_15/Code02_NumberOfIslands.java @@ -1,17 +1,17 @@ -package class09_14; +package class09_15; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Stack; -import class09_14.Code05_UnionFind.UnionSet; +public class Code02_NumberOfIslands { -public class Code06_IslandProblem { - - public static int solve1(int[][] board) { + public static int numIslands3(char[][] board) { int islands = 0; for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[0].length; j++) { - if (board[i][j] == 1) { + if (board[i][j] == '1') { islands++; infect(board, i, j); } @@ -20,81 +20,140 @@ public class Code06_IslandProblem { return islands; } - public static void infect(int[][] board, int i, int j) { - if (i < 0 || i == board.length || j < 0 || j == board[0].length || board[i][j] != 1) { + 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; } - board[i][j] = 2; + board[i][j] = 0; infect(board, i - 1, j); infect(board, i + 1, j); infect(board, i, j - 1); infect(board, i, j + 1); } - public static int solve2(int[][] board) { + public static int numIslands1(char[][] board) { int row = board.length; int col = board[0].length; Dot[][] dots = new Dot[row][col]; List dotList = new ArrayList<>(); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { - if (board[i][j] == 1) { + if (board[i][j] == '1') { dots[i][j] = new Dot(); dotList.add(dots[i][j]); } } } - UnionSet us = new UnionSet<>(dotList); + UnionFind1 uf = new UnionFind1<>(dotList); for (int j = 1; j < col; j++) { - if (board[0][j - 1] == 1 && board[0][j] == 1) { - us.union(dots[0][j - 1], dots[0][j]); + if (board[0][j - 1] == '1' && board[0][j] == '1') { + uf.union(dots[0][j - 1], dots[0][j]); } } for (int i = 1; i < row; i++) { - if (board[i - 1][0] == 1 && board[i][0] == 1) { - us.union(dots[i - 1][0], dots[i][0]); + if (board[i - 1][0] == '1' && board[i][0] == '1') { + uf.union(dots[i - 1][0], dots[i][0]); } } for (int i = 1; i < row; i++) { for (int j = 1; j < col; j++) { - if (board[i][j] == 1) { - if (board[i][j - 1] == 1) { - us.union(dots[i][j - 1], dots[i][j]); + if (board[i][j] == '1') { + if (board[i][j - 1] == '1') { + uf.union(dots[i][j - 1], dots[i][j]); } - if (board[i - 1][j] == 1) { - us.union(dots[i - 1][j], dots[i][j]); + if (board[i - 1][j] == '1') { + uf.union(dots[i - 1][j], dots[i][j]); } } } } - return us.sets(); + return uf.sets(); } public static class Dot { } - public static int solve3(int[][] board) { + public static class Node { + + V value; + + public Node(V v) { + value = v; + } + + } + + public static class UnionFind1 { + public HashMap> nodes; + public HashMap, Node> parents; + public HashMap, Integer> sizeMap; + + public UnionFind1(List values) { + nodes = new HashMap<>(); + parents = new HashMap<>(); + sizeMap = new HashMap<>(); + for (V cur : values) { + Node node = new Node<>(cur); + nodes.put(cur, node); + parents.put(node, node); + sizeMap.put(node, 1); + } + } + + public Node findFather(Node cur) { + Stack> path = new Stack<>(); + while (cur != parents.get(cur)) { + path.push(cur); + cur = parents.get(cur); + } + while (!path.isEmpty()) { + parents.put(path.pop(), cur); + } + return cur; + } + + public void union(V a, V b) { + Node aHead = findFather(nodes.get(a)); + Node bHead = findFather(nodes.get(b)); + if (aHead != bHead) { + int aSetSize = sizeMap.get(aHead); + int bSetSize = sizeMap.get(bHead); + Node big = aSetSize >= bSetSize ? aHead : bHead; + Node small = big == aHead ? bHead : aHead; + parents.put(small, big); + sizeMap.put(big, aSetSize + bSetSize); + sizeMap.remove(small); + } + } + + public int sets() { + return sizeMap.size(); + } + + } + + public static int numIslands2(char[][] board) { int row = board.length; int col = board[0].length; - UnionFind uf = new UnionFind(board); + UnionFind2 uf = new UnionFind2(board); for (int j = 1; j < col; j++) { - if (board[0][j - 1] == 1 && board[0][j] == 1) { + if (board[0][j - 1] == '1' && board[0][j] == '1') { uf.union(0, j - 1, 0, j); } } for (int i = 1; i < row; i++) { - if (board[i - 1][0] == 1 && board[i][0] == 1) { + if (board[i - 1][0] == '1' && board[i][0] == '1') { uf.union(i - 1, 0, i, 0); } } for (int i = 1; i < row; i++) { for (int j = 1; j < col; j++) { - if (board[i][j] == 1) { - if (board[i][j - 1] == 1) { + if (board[i][j] == '1') { + if (board[i][j - 1] == '1') { uf.union(i, j - 1, i, j); } - if (board[i - 1][j] == 1) { + if (board[i - 1][j] == '1') { uf.union(i - 1, j, i, j); } } @@ -103,14 +162,14 @@ public class Code06_IslandProblem { return uf.sets(); } - public static class UnionFind { + public static class UnionFind2 { private int[] parent; private int[] size; private int[] help; private int col; private int sets; - public UnionFind(int[][] board) { + public UnionFind2(char[][] board) { col = board[0].length; sets = 0; int row = board.length; @@ -120,7 +179,7 @@ public class Code06_IslandProblem { help = new int[len]; for (int r = 0; r < row; r++) { for (int c = 0; c < col; c++) { - if (board[r][c] == 1) { + if (board[r][c] == '1') { int i = index(r, c); parent[i] = i; size[i] = 1; @@ -169,20 +228,22 @@ public class Code06_IslandProblem { } - public static int[][] generateRandomMatrix(int row, int col) { - int[][] board = new int[row][col]; + // 为了测试 + public static char[][] generateRandomMatrix(int row, int col) { + char[][] board = new char[row][col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { - board[i][j] = Math.random() < 0.5 ? 1 : 0; + board[i][j] = Math.random() < 0.5 ? '1' : '0'; } } return board; } - public static int[][] copy(int[][] board) { + // 为了测试 + public static char[][] copy(char[][] board) { int row = board.length; int col = board[0].length; - int[][] ans = new int[row][col]; + char[][] ans = new char[row][col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { ans[i][j] = board[i][j]; @@ -191,12 +252,13 @@ public class Code06_IslandProblem { return ans; } + // 为了测试 public static void main(String[] args) { int row = 0; int col = 0; - int[][] board1 = null; - int[][] board2 = null; - int[][] board3 = null; + char[][] board1 = null; + char[][] board2 = null; + char[][] board3 = null; long start = 0; long end = 0; @@ -210,17 +272,17 @@ public class Code06_IslandProblem { System.out.println("随机生成的二维矩阵规模 : " + row + " * " + col); start = System.currentTimeMillis(); - System.out.println("感染方法的运行结果: " + solve1(board1)); + System.out.println("感染方法的运行结果: " + numIslands3(board1)); end = System.currentTimeMillis(); System.out.println("感染方法的运行时间: " + (end - start) + " ms"); start = System.currentTimeMillis(); - System.out.println("并查集(map实现)的运行结果: " + solve2(board2)); + System.out.println("并查集(map实现)的运行结果: " + numIslands1(board2)); end = System.currentTimeMillis(); System.out.println("并查集(map实现)的运行时间: " + (end - start) + " ms"); start = System.currentTimeMillis(); - System.out.println("并查集(数组实现)的运行结果: " + solve3(board3)); + System.out.println("并查集(数组实现)的运行结果: " + numIslands2(board3)); end = System.currentTimeMillis(); System.out.println("并查集(数组实现)的运行时间: " + (end - start) + " ms"); @@ -234,12 +296,12 @@ public class Code06_IslandProblem { System.out.println("随机生成的二维矩阵规模 : " + row + " * " + col); start = System.currentTimeMillis(); - System.out.println("感染方法的运行结果: " + solve1(board1)); + System.out.println("感染方法的运行结果: " + numIslands3(board1)); end = System.currentTimeMillis(); System.out.println("感染方法的运行时间: " + (end - start) + " ms"); start = System.currentTimeMillis(); - System.out.println("并查集(数组实现)的运行结果: " + solve3(board3)); + System.out.println("并查集(数组实现)的运行结果: " + numIslands2(board3)); end = System.currentTimeMillis(); System.out.println("并查集(数组实现)的运行时间: " + (end - start) + " ms"); diff --git a/src/class09_15/Code03_NumberOfIslandsII.java b/src/class09_15/Code03_NumberOfIslandsII.java new file mode 100644 index 0000000..ab61ed3 --- /dev/null +++ b/src/class09_15/Code03_NumberOfIslandsII.java @@ -0,0 +1,94 @@ +package class09_15; + +import java.util.ArrayList; +import java.util.List; + +public class Code03_NumberOfIslandsII { + + public static List numIslands2(int m, int n, int[][] positions) { + UnionFind unionFind = new UnionFind(m, n); + List ans = new ArrayList<>(); + for (int[] position : positions) { + unionFind.connect(position[0], position[1]); + ans.add(unionFind.sets()); + } + return ans; + } + + public static class UnionFind { + private int[] parent; + private int[] size; + private int[] help; + private final int col; + private final int row; + private int sets; + + public UnionFind(int m, int n) { + row = m; + col = n; + sets = 0; + int len = row * col; + parent = new int[len]; + size = new int[len]; + help = new int[len]; + } + + private int index(int r, int c) { + return r * col + c; + } + + private int find(int i) { + int hi = 0; + while (i != parent[i]) { + help[hi++] = i; + i = parent[i]; + } + for (hi--; hi >= 0; hi--) { + parent[help[hi]] = i; + } + return i; + } + + private void union(int r1, int c1, int r2, int c2) { + if (r1 < 0 || r1 == row || r2 < 0 || r2 == row || c1 < 0 || c1 == col || c2 < 0 || c2 == col) { + return; + } + int i1 = index(r1, c1); + int i2 = index(r2, c2); + if (size[i1] == 0 || size[i2] == 0) { + return; + } + int f1 = find(i1); + int f2 = find(i2); + if (f1 != f2) { + if (size[f1] >= size[f2]) { + size[f1] += size[f2]; + parent[f2] = f1; + } else { + size[f2] += size[f1]; + parent[f1] = f2; + } + sets--; + } + } + + public void connect(int i, int j) { + int index = index(i, j); + 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); + } + } + + public int sets() { + return sets; + } + + } + +}