问题描述

在一个班级里有N个同学, 有些同学是朋友,有些不是。他们之间的友谊是可以传递的比如A和B是朋友,B和C是朋友,那么A和C也是朋友。我们定义 friend circle为由直接或者间接都是朋友组成的group.

给定N*N 数组 M 代表同学之间的关系. 如果M[i][j] = 1, 那么i 和 j 同学是朋友,现在我们需要输出friend circles 的数量

分析

我们可以将给定的M数组看做是一个graph, M[i][j] = 1 表示节点i 和 j 相连,那么寻找fridend circle的问题,转化为图遍历的问题,求fiend circle的个数实则为求连通图的个数。解决这类问题通常使用DFS或者BFS去更新一个状态数组visited(保存节点是否被访问),对每个未访问的节点调用图形遍历算法,每次调用所有相连节点的状态都会被更新为已访问,那么friend cicle的数量则为调用遍历的次数。

DFS实现

public int findCircleNum(int[][] M) {
        int N = M.length;
        boolean[] visited = new boolean[N];
        int cnt = 0;
        for(int i = 0; i < N; i++){
            if(!visited[i]){
                dfs(M, visited, i);
                cnt++;
            }
        }
        return cnt;
    }

    private void dfs(int[][] M, boolean[] visited, int i){
        visited[i] = true;
        for(int j = 0; j < M.length; j++){
            if(M[i][j] == 1 && !visited[j]){
                dfs(M, visited, j);
            }
        }
    }

时间复杂度:O(n^2),总体上要遍历M数组的所有位置
空间复杂度:O(n)

BFS实现

   public int findCircleNum(int[][] M) {
        boolean[] visited = new boolean[M.length];
        int count = 0;
        Queue < Integer > queue = new LinkedList < > ();
        for (int i = 0; i < M.length; i++) {
            if (!visited[i]) {
                queue.add(i);
                while (!queue.isEmpty()) {
                    int s = queue.remove();
                    visited[s] = true;
                    for (int j = 0; j < M.length; j++) {
                        if (M[s][j] == 1 && !visited[j]])
                            queue.add(j);
                    }
                }
                count++;
            }
        }
        return count;
    }

时间复杂度:O(n^2),总体上要遍历M数组的所有位置
空间复杂度:O(n)

01-12 07:59