题目
There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends.
Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students.
Example 1:
Input: [[1,1,0], [1,1,0], [0,0,1]] Output: 2 Explanation:The 0th and 1st students are direct friends, so they are in a friend circle.
The 2nd student himself is in a friend circle. So return 2.
Example 2:
Input: [[1,1,0], [1,1,1], [0,1,1]] Output: 1 Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends,
so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return 1.
Note:
- N is in range [1,200].
- M[i][i] = 1 for all students.
- If M[i][j] = 1, then M[j][i] = 1.
思路
本题是个典型的union-find类型的题目。在《算法第四版》第一章的1.5中给出了union-find三种不同实现:
- quick-find
- quick-union
- 加权quick-union
本文实现了第二种方法,即quick-union算法。
思路如下:
首先我们设计一份API来封装所需的操作:连接两个索引并统计连通数、判断两个索引是否在一个连接分量中、找到根节点
API如下所示:
| API | 解释|
| ------------- |:-------------😐 -----😐
| bool connected(int p,int q) | 判断两个索引是否在一个连接分量中 |
| void unionnumber(int p, int q) | 连接两个索引并统计连通数|
|int find(int p)|找到根节点|
我们的解题步骤就是,先初始化变量,然后遍历矩阵右半角,遇到值为1先判断两个索引是否有相同的根节点,如果没有则连接索引,如果有则跳过继续循环。
代码
class Solution {
public:
int count;
vector<int> id;
bool connected(int p,int q){
return find(p)==find(q);
}
void unionnumber(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot)
return ;
id[pRoot] = qRoot;
count--;
//cout<<pRoot<<endl;
}
int findCircleNum(vector<vector<int>>& M) {
//将坐标作为索引
count = M.size();
int N = M.size();
for(int i=0;i<count;i++)
id.push_back(i);
//遍历M矩阵
for(int p=0;p<N;p++)
{
for(int q=p;q<N;q++)
{
if(M[p][q]==1)
{
if(connected(p,q)) continue;
unionnumber(p,q);
}
}
}
return count;
}
private:
int find(int p){
//找出根节点的名称
while(p!=id[p])
p = id[p];
return p;
}
};