题目来源:力扣
题目描述:
班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
=========================================================
示例 1:
输入:
[[1,1,0],
[1,1,0],
[0,0,1]]
输出: 2
说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
第2个学生自己在一个朋友圈。所以返回2。
===================================================
审题:
这道题较为简单,其本质是搜索连通分量的个数.我们可以从两个角度思考本题中连通分量个数的计算.
- 第一种思路是将二维矩阵视为无向图的二维矩阵结构,因此我们只需要搜索该无向图中的连通分量即可,可以使用广度优先搜索方法或深度优先搜索方法搜索所有连通分量.
- 第二中思路是使用并查集,如果矩阵(i,j)为1,则表示i与j为朋友关系,对应到并查集中即为i与j相连接,我们使用标准的并查集搜索方法很容易便可以计算图中连通分量个数.此处我们使用加权quick-union方法.
java算法:
无向图深度优先搜索
class Solution {
//使用深度优先搜索方法搜索无向图中连通分量个数
private void dfs(int[][]M, int s, boolean[] marked){
marked[s] = true;
for(int i = 0; i < M.length; i++){
if(M[s][i] == 1 && !marked[i]){
dfs(M, i, marked);
}
}
}
public int findCircleNum(int[][] M) {
boolean[] marked = new boolean[M.length];
int count = 0;
for(int i = 0; i < M.length; i++){
if(!marked[i]){
count++;
dfs(M, i, marked);
}
}
return count;
}
}
无向图广度优先搜索
class Solution {
//使用广度优先搜索算法搜索图中连通分量个数
private void bfs(int[][]M, int s, boolean[] marked){
Queue<Integer> queue = new LinkedList<>();
queue.offer(s);
marked[s] = true;
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0; i < size; i++){
int k = queue.poll();
for(int j = 0; j < M.length; j++){
if(M[k][j] == 1 && !marked[j]){
marked[j] = true;
queue.offer(j);
}
}
}
}
}
public int findCircleNum(int[][] M) {
boolean[] marked = new boolean[M.length];
int count = 0;
for(int i = 0; i < M.length; i++){
if(!marked[i]){
count++;
bfs(M, i, marked);
}
}
return count;
}
}
并查集加权quick-union算法
class Solution {
//计算连通分量数
//使用加权quick-union并查集算法
private int[] id;
private int[] sz;
private int count;
private int find(int p){
while(p != id[p])
p = id[p];
return p;
}
private void union(int p, int q){
int pID = find(p);
int qID = find(q);
if(pID == qID)
return;
if(sz[pID] < sz[qID]){
id[pID] = qID;
sz[qID] += sz[pID];
}
else{
id[qID] = pID;
sz[pID] += sz[qID];
}
count--;
}
public int findCircleNum(int[][] M) {
count = M.length; //初始化连通分量为n
id = new int[M.length];
sz = new int[M.length];
for(int i = 0; i < M.length; i++){
id[i] = i;
sz[i] = 1;
}
for(int i = 0; i < M.length; i++){
for(int j = 0; j < M.length; j++){
if(M[i][j] == 1)
union(i, j);
}
}
return count;
}
}