leetcode 547 省份数量

思路一:使用深度优先搜索,递归。为每一个节点设置一个标志表示是否已经被访问;每次遍历矩阵的一行,若该行之前未被访问过,则进行dfs。在dfs中首先将该点标记为已经访问过,并且遍历节点该行,若有值为一则递归dfs。最终一个节点之前要是被访问过,就不满足条件,res也不会增加。

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size(), res = 0;
        vector<bool> visited(n, false);
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                dfs(isConnected, i, visited);
                ++res;
            }
        }
        return res;
    }

    void dfs(vector<vector<int>>& isConnected, int i, vector<bool>& visited) {
        visited[i] = true;
        for (int k = 0; k < isConnected.size(); k++) {
            if (isConnected[i][k] == 1 && !visited[k]) {
                dfs(isConnected, k, visited);
            }
        }
    }
};

思路二:使用并查集的概念,一开始每个节点都是单独一类,然后逐渐合并。具体是利用了树,每个节点找到他的根节点,如果和前者根节点相同,则合并,且省份减一。

class Solution {
public:
    vector<int> roots; // 保存每个节点的根节点,根节点相同的节点即属于同一类。
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size(), ans = n;
        init(n);
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (isConnected[i][j] == 1 && merge(i, j)) {
                    ans--;
                }
            }
        }
        return ans;
    }
    void init(int n) { // 初始化每个节点都是单独一类,所以他们的根节点就是他们本身。
        roots.resize(n);
        for (int i = 0; i < n; ++i) {
            roots[i] = i;
        }
    }
    int find(int x) {
        int temp = x;
        while (roots[temp] != temp) { // 第一个循环用于找到该节点的根节点。
            temp = roots[temp];
        }
        while (roots[x] != x) { // 第二个循环用于把每次合并后,把子树上的每点的roots都直接指向根节点。从而使树深度趋近于二,不至于深度过深,使复杂度达到O(n)。
            int t = roots[x];
            roots[x] = temp;
            x = t;
        }
        return x;
    }
    bool merge(int u, int v) {
        int ru = find(u);
        int rv = find(v);
        if (ru == rv) { // 根节点相同则已经合并完成了,不用再次合并减少集合数量。
            return false;
        }
        roots[ru] = rv;
        return true;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值