LeetCode每日一题--547. 省份数量(广度优先搜索 深度优先搜索 并查集)

题目:跳转至 547. 省份数量
有 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]
class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {

    }
};

思路:
方法一:深度优先遍历
用 visited 标记是否访问过这个城市,没有就从这个城市深度优先搜索,再查看是否还存在没有访问过的城市,有则继续搜索。

class Solution {
public:
    void dfs(vector<vector<int>>& isConnected,vector<int>& visited,int provinces,int i){
        for(int j=0;j<provinces;++j){
            if(isConnected[i][j]==1 && !visited[j]){  //如果i,j城市相连,那j也已被访问
                visited[j]=1;
                dfs(isConnected,visited,provinces,j);  //遍历与j相连的城市
            }
        }
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        int provinces=isConnected.size();
        vector<int> visited(provinces,0);  //初始都没访问过
        int count=0;
        for(int i=0;i<provinces;++i){
            if(!visited[i]){  //如果没有访问过这个城市
                visited[i]=1;
                dfs(isConnected,visited,provinces,i);  //遍历与i相连的城市
                ++count;  //不相连的省份个数
            }
        }
        return count;
    }
};

方法二:广度优先遍历
用 visited 标记是否访问过这个城市,没有就从这个城市广度优先搜素,利用队列存储其他待访问的城市。

和上边不一样的就是一个是把与 i 相连的城市 j 访问完后继续访问与 j 相连的 k,直到没有未访问过的再回过头访问与 i 相连的城市 m,一个是先把与 i 相连的城市 j,m,n都访问完同时记录下 j,m,n,再挨个访问 j,m,n。

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int provinces=isConnected.size();
        vector<int> visited(provinces,0);  //初始都没访问过
        int count=0;
        for(int i=0;i<provinces;++i){
            if(!visited[i]){  //如果没有访问过这个城市
                visited[i]=1;
                queue<int> que;  //用队列存储遇到的之后要遍历的省份
                que.push(i);
                while(!que.empty()){
                    int tmp=que.front();  //每次判断与队首tmp相连的城市
                    que.pop();
                    for(int j=0;j<provinces;++j){
                        if(isConnected[tmp][j]==1 && !visited[j]){ //城市i,j相连且j未访问过
                            visited[j]=1;
                            que.push(j);
                        }
                    }
                }
                ++count;  //不相连的省份个数
            }
        }
        return count;
    }
};

方法三:并查集
上一题就是并查集,先自己简单回顾下,并查集是在有 n 个元素的集合应用中,先让每个元素各自构成一个集合,再按顺序将属于同一组的集合合并,其间反复查找一个元素在哪个集合中。
所以需要如下功能:

  • 查找自身根节点
  • 合并集合
  • 为了优化查询时间,可以压缩路径,使每个查询节点(非自身父节点)都能直接指向自身父节点

这里不带权值比上一题简单。

class Solution {
public:
    int findf(vector<int>& parent,int i){
        if(parent[i]!=i){  //如果不是自身的父节点,递归判断自身的父节点是不是他的父节点
            parent[i]=findf(parent,parent[i]);  //并压缩节点路径,直接指向根节点
        }
        return parent[i];  //返回父节点
    }
    
    void merge(vector<int>& parent,int i,int j){
        parent[findf(parent,i)]=findf(parent,j);  //把i的父节点设成j的父节点(把i合并到j的集合中)
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        int provinces=isConnected.size();
        vector<int> parent(provinces);
        for(int i=0;i<provinces;++i)
            parent[i]=i;  //初始每个节点父节点都是自身

        for(int i=0;i<provinces;++i){
            for(int j=0;j<provinces;++j){
                if(isConnected[i][j]==1)
                    merge(parent,i,j);  //如果i,j城市相连,合并两个集合
            }
        }

        int count=0;
        for(int i=0;i<provinces;++i){
            if(parent[i]==i)  //每个集合中只有一个节点的父节点是自身
                ++count;
        }
        return count;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值