547. Friend Circles

Medium
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.

这道题跟Number of islands有异曲同工之处,都是先遍历,然后标记,然后标记周围的。就像Number of islands吃掉所有相连的岛屿一样,本题在遍历每一个人时,也要将他的朋友全部标记为已访问,这里我们用了一个boolean[] visited来记录。这样的话,所有直接或者间接的朋友(直观来讲就是相连的人)都会被标记。我们计算没有跟其他人连在一起的人的个数,就是最后的独立的朋友圈个数。注意分清楚这里的visited[]和原来的int[][] M. 原来的二维数组用来判断两个人是不是 朋友,而visited[]用来标记是否被访问过。

这个讲解很有帮助:
547. Friend Circles

class Solution {
    public int findCircleNum(int[][] M) {
        int n = M.length;
        if (M == null || n == 0){
            return 0;
        }
        boolean[] visited = new boolean[n];
        int ans = 0;
        for (int i = 0; i < n; i++){
            if (visited[i]){
                continue;
            } else {
                ans++;
                helper(M, i, n, visited);
            }
        }
        return ans;
    }
    
    private void helper(int[][] M, int curt, int n, boolean[] visited){
        visited[curt] = true;
        for (int j = 0; j < n; j++){
            if (M[curt][j] == 1 && !visited[j]){
                helper(M, j, n, visited);
            }
        }
    }
}

这道题还可以用并查集做。 UnionFind是一个特别好用的工具,你不去看你就永远不知道,你练几道题就会发现用它来解决某一类型的问题比dfs简单得多还快。而且会用UnionFind解题的人据我所知是不多的。做这道题之前我复习了一下算法高级班里UnionFind的模版跟Number of Connected Components in an Undirected Graph这个题, UnionFind可以很快上手。

class Solution {
    public int[] father;
    public int n;
    public int findCircleNum(int[][] M) {
        if (M == null || M.length == 0 || M[0].length == 0){
            return 0;
        }    
        n = M.length;
        father = new int[n];
        for (int i = 0; i < n; i++){
            father[i] = i;
        }
        int res = n;
        for (int i = 0; i < n; i++){
            for (int j = 0; j < n; j++){
                if (M[i][j] == 1 && find(i) != find(j)){
                    union(i, j);
                    res--;
                }    
            }
        }
        return res;
    }
    
    private int find(int i){
        if (father[i] == i){
            return i;
        }
        return find(father[i]);
    }
    
    private void union(int a, int b){
        int root_a = find(a);
        int root_b = find(b);
        if (root_a != root_b){
            father[root_a] = root_b;
        }
    }
}
    原文作者:greatfulltime
    原文地址: https://www.jianshu.com/p/8c702332dfa6
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞