547. Friend Circles

题目

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:

  1. N is in range [1,200].
  2. M[i][i] = 1 for all students.
  3. 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;
        }
    
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Roaring Kitty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值