leetcode_547_朋友圈_并查集解法
1 package cn.leetcode.circleoffriends_547; 2 3 import java.util.HashSet; 4 5 /** 6 * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 7 * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 8 * 9 * 示例 1: 10 * 输入: 11 * [[1,1,0], 12 * [1,1,0], 13 * [0,0,1]] 14 * 输出:2 15 * 解释:已知学生 0 和学生 1 互为朋友,他们在一个朋友圈。 16 * 第2个学生自己在一个朋友圈。所以返回 2 。 17 * 18 * 示例 2: 19 * 输入: 20 * [[1,1,0], 21 * [1,1,1], 22 * [0,1,1]] 23 * 输出:1 24 * 解释:已知学生 0 和学生 1 互为朋友,学生 1 和学生 2 互为朋友,所以学生 0 和学生 2 也是朋友,所以他们三个在一个朋友圈,返回 1 。 25 * 26 * 提示: 27 * 1 <= N <= 200 28 * M[i][i] == 1 29 * M[i][j] == M[j][i] 30 * 31 * 参考资料:https://www.cnblogs.com/noKing/p/8018609.html 32 */ 33 public class Solution { 34 35 public static void main(String[] args) { 36 // int[][] arr = new int[][]{{1, 1, 0}, {1, 1, 0}, {0, 0, 1}}; 37 int[][] arr = new int[][]{{1, 0, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1}, {1, 0, 1, 1}}; 38 Solution s = new Solution(); 39 40 System.out.println(s.findCircleNum(arr)); 41 } 42 43 /** 44 * 一共又多少个朋友圈 45 * @param M 46 * @return 47 */ 48 public int findCircleNum(int[][] M) { 49 UnionFind union = new UnionFind(M.length); 50 int ret = union.findCircleNum(M); 51 // union.printArr(); 52 return ret; 53 } 54 55 56 } 57 58 /** 59 *并查集具体实现 60 */ 61 class UnionFind { 62 private static int[] leader; 63 private static int[] weight; 64 private static int size; 65 66 /** 67 * 一共有多少个组 68 * @param M 69 * @return 70 */ 71 public static int findCircleNum(int[][] M) { 72 for (int i = 0; i < M.length; i++) { 73 for (int j = 0; j < M[i].length; j++) { 74 if (M[i][j] != 0 && i != j) { 75 unionElements(i, j); 76 } 77 } 78 } 79 //用HashSet不重复性记录有多少个不同的组 80 int leaderVal=0; 81 HashSet<Integer> set = new HashSet(); 82 for (int i = 0; i < leader.length; i++) { 83 leaderVal=find(leader[i]); 84 set.add(leaderVal); 85 } 86 return set.size(); 87 } 88 89 /** 90 * 构造函数 91 * @param size 92 */ 93 public UnionFind(int size) { 94 this.leader = new int[size]; 95 this.weight = new int[size]; 96 this.size = size; 97 for (int i = 0; i < size; i++) { 98 this.leader[i] = i; 99 this.weight[i] = 1; 100 } 101 } 102 103 /** 104 * 查询最终teamLeader的值 105 * @param element 106 * @return 107 */ 108 public static int find(int element) { 109 while (element != leader[element]) { 110 leader[element] = leader[leader[element]]; // 路径压缩 (非最终leader结点) 111 element = leader[element]; 112 } 113 return element; 114 } 115 116 public static boolean isConnected(int firstElement, int secondElement) { 117 return find(firstElement) == find(secondElement); 118 } 119 120 public static void unionElements(int firstElement, int secondElement) { 121 int firstRoot = find(firstElement); 122 int secondRoot = find(secondElement); 123 124 //如果已经属于同一个集合了,就不用再合并了。 125 if (firstRoot == secondRoot) { 126 return; 127 } 128 //谁小弟多谁说了算 129 if (weight[firstRoot] > weight[secondRoot]) { 130 leader[secondRoot] = firstRoot; 131 weight[firstRoot] += weight[secondRoot]; 132 } else { 133 leader[firstRoot] = secondRoot; 134 weight[secondRoot] += weight[firstRoot]; 135 } 136 } 137 138 public static void printArr() { 139 for (int p : leader) { 140 System.out.print(p + "\t"); 141 } 142 System.out.println(); 143 } 144 145 }