夯实算法-省份数量

139 阅读2分钟

题目:省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

示例 1:

输入: isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出: 2

示例 2:

输入: isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出: 3

提示:

  • 1 <= n <= 200
  • n == isConnected.length
  • n == isConnected[i].length
  • isConnected[i][j] 为 1 或 0
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]

解题思路

  • 从题目描述来看,显然这是一个使用邻接矩阵表示的图,图中结点就是编号从0到M的学生,所谓的朋友圈就是一个连通子图。所以问题就变为在无向图中找连通子图的数量。
  • 使用 boolean[] marked = new boolean[n];表示结点的访问情况,int count计数连通子图的数量。
  • 定义void dfs2(int[][] M, int v, boolean[] marked),使用深度优先访问连通子图的所有结点。
    • 遍历所有结点[0, n - 1],如果节点没有被访问过,且两个结点之间有边连接(M[i][j] = 1,表示已知第i个和j个学生互为朋友关系),就将该结点表示为已访问marked[i] = true;,然后递归地调用。
  • 主函数遍历所有结点[0, n - 1],每当发现没有被访问的结点,说明这是一个新的连通子图。所以count++,然后将该结点设置为已访问,调用 dfs2(M, i, marked);。这个调用就可以将包括该结点的连通子图中所有结点都访问到。

代码实现

public int findCircleNum(int[][] M) {
    int count = 0;
    n = M.length;
    boolean[] marked = new boolean[n];
    for (int i = 0; i < n; i++) {
        if (!marked[i]) {
            count++;
            marked[i] = true;
            dfs2(M, i, marked);
        }
    }
    return count;
}

private void dfs2(int[][] M, int v, boolean[] marked) {
    for (int i = 0; i < n; i++) {
        if (!marked[i] && M[v][i] == 1) {
            marked[i] = true;
            dfs2(M, i, marked);
        }
    }
}

运行结果

zby.png

复杂度分析

  • 空间复杂度:O(n)
  • 时间复杂度:O(n^2)

掘金(JUEJIN) 一起分享知识, Keep Learning!