力扣 547. 省份数量

这是一篇关于LeetCode第547题的博客,主要讨论如何计算矩阵中省份的数量。文章详细介绍了使用并查集和深度优先搜索(DFS)两种方法来解决此问题,其中并查集的关键在于找到节点的根节点,DFS则通过遍历和标记访问状态来找出连通的节点。
摘要由CSDN通过智能技术生成

题目

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

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

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

返回矩阵中 省份 的数量。

题解

1、并查集

并查集有两个操作,find操作用于查找该节点属于哪个圈子,union操作合并圈子。

并查集初始时每个节点都是一个圈子,每个节点的圈子都指向自己,每次union合并操作,会把一个圈子a的根节点指向另一个圈子b的根节点,这样圈子a的所有节点的根节点也会跟着指向圈子b的根节点,达到合并的目的。

这里主要是因为圈子a中其他节点的根节点本来就不是他自己,因此在最后计算的时候不会看作省份,只有根节点是本身的节点才会看作是一个省份,因此当a圈和b圈相连,修改a圈根节点的指向,就可以保证ab圈的节点中只有一个是指向本身的。

class Solution {

    // 寻找树根
    int Find(int[] root, int index){
        if(root[index] != index){  //说明当前节点的根不是自己,需要往上找
            return Find(root, root[index]);
        }
        return root[index];  // 节点的根是自己,找到了根
    }

    void Union(int[] root, int i, int j){
        // 将一个根节点指向另一个根节点
        root[Find(root, i)] = Find(root, j);
    }

    // 初始每个节点的根指向自己,然后查找相连的,将相连的合并指向同一个根节点
    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        int[] root = new int[n];
        // 每个节点的根初始指向自己
        for(int i = 0; i < n; i++){
            root[i] = i;
        }

        // 查并集
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                if(isConnected[i][j] == 1){  //两个城市相连
                    Union(root, i, j);
                }
            }
        }

        // 计数,有多少个节点的根还是自己,那么就有多少省份
        int count = 0;
        for(int i = 0; i < n; i++){
            if(root[i] == i) count++;
        }
        return count;
    }
}

2、DFS

设置城市访问状态数组visited,初始值均为0。

对每个节点通过深度搜索寻找与其直接或间接连通的节点。

遍历所有节点,对于直接连通的节点 t 将其访问状态改为1,然后从节点 t 出发寻找连通的节点。

class Solution {
    // 采用dfs方法
    public int findCircleNum(int[][] isConnected) {
        // 使用visited数组来表明是否访问过,若没有访问过,则结果+1,然后对该节点进行深搜
        int count = 0;
        int n = isConnected.length;
        int[] visited = new int[n];
        for(int i = 0; i < n; i++){
            if(visited[i] == 0){
                count++;
                dfs(isConnected, visited, i);  // 深搜节点i的连通节点
            }
        }
        return count;
    }

    void dfs(int[][] isConnected, int[] visited, int index){
        for(int j = 0; j < isConnected.length; j++){
            if(isConnected[index][j] == 1 && visited[j] != 1){  //连通并且没访问过
                visited[j] = 1;  // 进入连通但未访问过的节点j,修改访问状态
                dfs(isConnected, visited, j);  //从j出发开始遍历,寻找连通节点
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值