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 }