leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 76 】2021-11-24 - 547. 省份数量 #95

Open azl397985856 opened 2 years ago

azl397985856 commented 2 years ago

547. 省份数量

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/number-of-provinces/

前置知识

暂无

题目描述

有 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]
ginnydyy commented 2 years ago

Problem

https://leetcode.com/problems/number-of-provinces/

Notes

Solution

Complexity

falconruo commented 2 years ago

思路: 方法一、Hashmap/set/数组 + DFS 方法二、Hashmap/set/数组 + BFS 方法三、并查集

方法一、Hashmap + DFS

方法二、Hashmap + BFS

方法三、Union Find

代码(C++):

方法三、
class UnionFind {
    vector<int> parent;
public:
    int circle;
    UnionFind(int n) {
        parent = vector<int>(n, 0);

        circle = n;

        for (int i = 0; i < n; ++i)
            parent[i] = i;
    }

    int Find(int x) {
        int r = x;

        while (r != parent[r])
            r = parent[r];

        return r;
    }

    void Union(int x, int y) {
        int p = Find(x);
        int q = Find(y);

        if (p != q) {
            parent[p] = q;
            circle--;
        }
    }
};

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size();

        UnionFind u(n);

        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (isConnected[i][j]) {
                    u.Union(i, j);
                }
            }
        }

        return u.circle;
    }
};
zhiyuanpeng commented 2 years ago
class UF:
    def __init__(self, n) -> None:
        self.parent = {i: i for i in range(n)}
        self.size = n

    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]

    def connect(self, i, j):
        root_i, root_j = self.find(i), self.find(j)
        if root_i != root_j:
            self.size -= 1
            self.parent[root_i] = root_j

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        n = len(isConnected)
        uf = UF(n)
        for i in range(n):
            for j in range(n):

                if isConnected[i][j]:
                    uf.connect(i, j)
        return uf.size
asterqian commented 2 years ago

思路

union find

代码

class Solution {
public:
    int find(vector<int>& parent, int idx) {
        if (parent[idx] != idx) {
            parent[idx] = find(parent, parent[idx]);
        }
        return parent[idx];
    }
    void getUnion(vector<int>& parent, int idx1, int idx2) {
        parent[find(parent, idx1)] = find(parent, idx2);
    }
    int findCircleNum(vector<vector<int>>& isConnected) {
        vector<int> parent(isConnected.size());
        for (int i = 0; i < isConnected.size(); ++i) {
            parent[i] = i;
        }
        for (int i = 0; i < isConnected.size(); ++i) {
            for (int j = i + 1; j < isConnected.size(); ++j) {
                if (isConnected[i][j] == 1) {
                    getUnion(parent, i, j);
                }
            }
        }
        int res = 0;
        for (int i = 0; i < parent.size(); ++i) {
            if (parent[i] == i) res++;
        }
        return res;
    }
};

Time Complexity: O(n^2logn)

Space Complexity: O(n)

ZJP1483469269 commented 2 years ago

思路

数组+bfs

代码

class Solution {
    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        boolean[] visited = new boolean[n];
        int ans = 0;
        LinkedList<Integer> dq = new LinkedList<>();
        for(int j = 0;j < n ;j++){
            if(!visited[j]){
                ans++;
                dq.offer(j);
                visited[j] = true;
                while(!dq.isEmpty()){
                    int x = dq.poll();
                    for(int i = 0; i< n ; i++){
                        if(!visited[i] && isConnected[x][i] == 1){
                            dq.offer(i);
                            visited[i] = true;
                        }
                    }
                }
            }
        }
        return ans;
    }
}

复杂度分析

时间复杂度:O(n*n) 空间复杂度:O(n)

XinnXuu commented 2 years ago
//DFS
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int count = 0;
        boolean[] visited = new boolean[isConnected.length];
        for (int i = 0; i < isConnected.length; i++){
            if(!visited[i]){ //新的连通分量
                dfs(isConnected,visited,i);
                count++;
            }
        }
        return count++;
    }
    public void dfs (int[][] isConnected, boolean[] visited, int i){
        for(int j = 0; j < isConnected.length; j++) {
            if (isConnected[i][j] == 1 && visited[j] != true){
                visited[j] = true; //标记在同一个连通分量的城市
                dfs(isConnected,visited,j);
            }
        }
    }
}
kennyxcao commented 2 years ago

547. Number of Provinces

Intuition

Code

/**
 * @param {number[][]} isConnected
 * @return {number}
 */
const findCircleNum3 = function(isConnected) { // Union Find, Time: O(n^2), Space: O(n)
  const n = isConnected.length;
  const dsu = new DSU(n);
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      if (isConnected[i][j] && i !== j) {
        dsu.union(i, j);
      }
    }
  }
  return dsu.count;
};

class DSU {
  constructor(n) {
    this.parent = Array.from(Array(n).keys());
    this.count = n;
  }

  find(x) {
    if (this.parent[x] !== x) {
      this.parent[x] = this.find(this.parent[x]); // path compression
    }
    return this.parent[x];
  }

  union(x, y) {
    const rootX = this.find(x);
    const rootY = this.find(y);
    if (rootX !== rootY) {
      this.parent[Math.min(rootX, rootY)] = Math.max(rootX, rootY);
      this.count -= 1;
    }
  }
}

Complexity Analysis

chen445 commented 2 years ago

思路

Using Union Find

代码

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        union_map=list(range(len(isConnected)))
        count=len(isConnected)
        def find(a):
            while union_map[a] !=a:
                a=union_map[a]
            return a
        def union(a,b):
            nonlocal count
            a_root=find(a)
            b_root=find(b)
            if a_root != b_root:
                count-=1
                union_map[b_root]=a_root
        for i in range(len(isConnected)):
            for j in range(i+1,len(isConnected)):
                if isConnected[i][j]==1:
                    union(i,j)
        return count

复杂度

Time: O(n*2logn) n is the length of isConnected

Space: O(n)

machuangmr commented 2 years ago

代码

class UnionFind {
    // 记录父节点
    private Map<Integer,Integer> father;
    // 记录集合的数量
    private int numOfSets = 0;

    public UnionFind() {
        father = new HashMap<Integer,Integer>();
        numOfSets = 0;
    }

    public void add(int x) {
        if (!father.containsKey(x)) {
            father.put(x, null);
            numOfSets++;
        }
    }

    public void merge(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);

        if (rootX != rootY){
            father.put(rootX,rootY);
            numOfSets--;
        }
    }

    public int find(int x) {
        int root = x;

        while(father.get(root) != null){
            root = father.get(root);
        }

        while(x != root){
            int original_father = father.get(x);
            father.put(x,root);
            x = original_father;
        }

        return root;
    }

    public boolean isConnected(int x, int y) {
        return find(x) == find(y);
    }

    public int getNumOfSets() {
        return numOfSets;
    }
}

class Solution {
    public int findCircleNum(int[][] isConnected) {
        UnionFind uf = new UnionFind();
        for(int i = 0;i < isConnected.length;i++){
            uf.add(i);
            for(int j = 0;j < i;j++){
                if(isConnected[i][j] == 1){
                    uf.merge(i,j);
                }
            }
        }

        return uf.getNumOfSets();
    }
}

复杂度

florenzliu commented 2 years ago

Explanation

Code

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        adj = defaultdict(list)
        for a in range(len(isConnected)):
            for b in range(len(isConnected[0])):
                if a != b  and isConnected[a][b] == 1:
                    adj[a].append(b)

        def dfs(n):
            nonlocal count, adj, visited
            visited.add(n)
            for i in adj[n]:
                if i not in visited:
                    dfs(i)
        visited = set()
        count = 0
        for k in adj.keys():
            if k not in visited:
                count += 1
                dfs(k)

        return count + len(isConnected) - len(visited)

Time complexity: O(v+e) where v is the length of cities and e is the edge/connection between cities

Space complexity: O(v+e)

muimi commented 2 years ago

思路

并查集

代码

class UnionFind {
  int[] parent;
  int size;
  public UnionFind(int n) {
    size = n;
    parent = new int[n];
    for (int i = 0; i < n; i++) parent[i] = i;
  }
  public int find(int i) {
    while (parent[i] != i) i = parent[i];
    return i;
  }
  public void union(int i, int j) {
    int pi = find(i);
    int pj = find(j);
    if (pi != pj) {
      parent[pi] = pj;
      size--;
    }
  }
  public int size() {
    return size;
  }
}
class Solution {
  public int findCircleNum(int[][] isConnected) {
    int n = isConnected.length;
    UnionFind uf = new UnionFind(n);
    for (int i = 0; i < n - 1; i++) {
      for (int j = i + 1; j < n; j++) {
        if (isConnected[i][j] == 1) uf.union(i, j);
      }
    }
    return uf.size();
  }
}
biscuit279 commented 2 years ago

思路 并查集

class Solution(object):
    def findCircleNum(self, isConnected):
        """
        :type isConnected: List[List[int]]
        :rtype: int
        """
        def find(index):
            if parent[index] != index:
                parent[index] = find(parent[index])
            return parent[index]

        def union(index1, index2):a
            parent[find(index1)] = find(index2)

        provinces = len(isConnected)
        parent = list(range(provinces))

        for i in range(provinces):
            for j in range(i + 1, provinces):
                if isConnected[i][j] == 1:
                    union(i, j)

        circles = sum(parent[i] == i for i in range(provinces))
        return circles

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

cecilialmw commented 2 years ago
class Solution {
    public int findCircleNum(int[][] isConnected) {
        Map<Integer, String> visited = new HashMap<Integer, String>();

        for (int i = 0; i < isConnected.length; i++) {
            visited.put(i, "unvisited");
        }

        int connected_num = 0;

        for (int i = 0; i < isConnected.length; i++) {
            if (visited.get(i) == "unvisited") {
                connected_num += 1;
                dfs(visited, i, isConnected);
            } 
        }

        return connected_num;
    }

    public void dfs(Map visited, int city, int[][] isConnected) {
        visited.put(city, "pending");

        for (int i = 0; i< isConnected.length; i++) {
            if ((isConnected[city][i] == 1) & (visited.get(i) == "unvisited")) {
                dfs(visited, i, isConnected);               
            }
        }
        visited.put(city, "visited");
    }
}

Complexity:

time: O(n)

space: O(n)

july-aha commented 2 years ago
var findCircleNum = function (isConnected) {
    let city = isConnected.length;
    let visited = new Array(city);
    let count = 0;
    function dfs(now, isConnected, visited) {//深度优先遍历
        if (!visited[now]) {
            visited[now]=true;
            for (let i = 0; i < isConnected[now].length; i++) {
                //该节点联通的所有节点
                if (isConnected[now][i]) {
                    //向下遍历
                    dfs(i, isConnected,visited)
                }
            }
        }else{
            return;
        }
    }
    for(let start=0;start<city;start++){
        if(!visited[start]){
            count++;//每一个不被访问过的都是一个联通域
            dfs(start,isConnected,visited)
        }
    }

    return count;
};

时间复杂度:O(nn)//遍历nn的邻接矩阵 空间复杂度:O(n)

KennethAlgol commented 2 years ago

public class Solution {
    public void dfs(int[][] M, int[] visited, int i) {
        for (int j = 0; j < M.length; j++) {
            if (M[i][j] == 1 && visited[j] == 0) {
                visited[j] = 1;
                dfs(M, visited, j);
            }
        }
    }
    public int findCircleNum(int[][] M) {
        int[] visited = new int[M.length];
        int count = 0;
        for (int i = 0; i < M.length; i++) {
            if (visited[i] == 0) {
                dfs(M, visited, i);
                count++;
            }
        }
        return count;
    }
}
Zhi22 commented 2 years ago

DFS

class Solution:
    def __init__(self):
        self.isConnected = None
        self.n = 0
        self.res = 0
        self.visited = None

    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        self.isConnected = isConnected
        self.n = len(isConnected)
        self.visited = [0] * self.n
        for i in range(self.n):
            if not self.visited[i]:
                self.dfs(i)
                self.res += 1
        return self.res

    def dfs(self, i):
        for j in range(self.n):
            if i != j and self.isConnected[i][j] and not self.visited[j]:
                self.visited[j] = 1
                self.dfs(j)

BFS

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        n = len(isConnected)
        visited = [0] * n
        deque = collections.deque()
        res = 0
        for i in range(n):
            if not visited[i]:
                res += 1
                visited[i] = 1
                deque.append(i)
            while len(deque):
                curr = deque.popleft()
                for j in range(n):
                    if j != curr and isConnected[curr][j] and not visited[j]:
                        deque.append(j)
                        visited[j] = 1
        return res

Union Find

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        def find(index: int):
            if parent[index] != index:
                parent[index] = find(parent[index])
            return parent[index]
        def union(index_1: int , index_2: int):
            parent[find(index_1)] = find(index_2)
        n = len(isConnected)
        parent = list(range(n))
        for i in range(n):
            for j in range(i+1, n):
                if isConnected[i][j]:
                    union(i, j)
        return sum(parent[i] == i for i in range(n))
RonghuanYou commented 2 years ago
class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        N = len(isConnected)
        res = 0

        parent = [i for i in range(N)]
        def union(parent, i, j):
            parent[find(parent, i)] = find(parent, j)

        def find(parent,i):
            while parent[i] != i:
                parent[i] = parent[parent[i]]
                i = parent[i]
            return i

        for i in range(N):
            for j in range(N):
                if isConnected[i][j] == 1:
                    union(parent, i, j)

        for i in range(N):
            if parent[i] == i:
                res += 1

        return res
mokrs commented 2 years ago
class Solution {
private:
    int Find(vector<int>& parent, int index) {
        if (parent[index] != index) {
            parent[index] = Find(parent, parent[index]);
        }

        return parent[index];
    }

    void Union(vector<int>& parent, int index1, int index2) {
        parent[Find(parent, index1)] = Find(parent, index2);
    }

public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int count = isConnected.size();
        vector<int> parent(count);
        for (int i = 0; i < count; ++i) {
            parent[i] = i;
        }

        for (int i = 0; i < count; i++) {
            for (int j = i + 1; j < count; ++j) {
                if (isConnected[i][j] == 1) {
                    Union(parent, i, j);
                }
            }
        }

        int res = 0;
        for (int i = 0; i < count; ++i) {
            if (parent[i] == i) {
                ++res;
            }
        }

        return res;
    }
};

并查集,第一次听说^^

carterrr commented 2 years ago
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int length = isConnected.length;
        UF uf = new UF(length);
        for(int i = 0 ; i< length ; i++) {
            for(int j = i + 1; j< length ; j ++) {
                if(isConnected[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }
        return uf.size;
    }

    private class UF{
        int size;
        final int[] node;
        public UF(int length) {
            this.node = new int[length];
            int idx = 0;
            while(idx <= this.node.length - 1) {
                node[idx] = idx;
                idx ++;
            }
            this.size = length;
        }

        public void union(int p, int q) {
            p = findRoot(p);
            q = findRoot(q);
            if(p != q){
                node[p] = q;
                // 合并两个节点的根 孤岛减少一个
                this.size --;
            } 
        }

        private int findRoot_slow(int p) {
            while(node[p] != p) {
                p = node[p];
            }
            return p;
        }

        // 这种更快
        private int findRoot(int p) {
            if(node[p] == p) {
                return p;
            }
            // 级联修改  遍历路径上每个都改
            // 同时压缩节点到根节点的值路径
            return node[p] = findRoot(root[p]);
        }
    }
}
JinhMa commented 2 years ago

class Solution { public int findCircleNum(int[][] isConnected) { int provinces = isConnected.length; int[] parent = new int[provinces]; for (int i = 0; i < provinces; i++) { parent[i] = i; } for (int i = 0; i < provinces; i++) { for (int j = i + 1; j < provinces; j++) { if (isConnected[i][j] == 1) { union(parent, i, j); } } } int circles = 0; for (int i = 0; i < provinces; i++) { if (parent[i] == i) { circles++; } } return circles; }

public void union(int[] parent, int index1, int index2) {
    parent[find(parent, index1)] = find(parent, index2);
}

public int find(int[] parent, int index) {
    if (parent[index] != index) {
        parent[index] = find(parent, parent[index]);
    }
    return parent[index];
}

}

Laurence-try commented 2 years ago

思路

dfs

代码

使用语言:Python3

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        visited = [0] * len(isConnected)
        count = 0
        for i in range(len(isConnected)):
            if visited[i] == 0:
                self.dfs(isConnected, visited, i)
                count += 1
        return count

    def dfs(self, isConnected, visited, i):
        for j in range(len(isConnected)):
            if isConnected[i][j] == 1 and visited[j] == 0:
                visited[j] = 1
                self.dfs(isConnected, visited, j)

复杂度分析 时间复杂度:O(n^2), n is the number of city 空间复杂度:O(n)

hellowxwworld commented 2 years ago

并查集

int ufsFind(vector<int>& ufs, int x) {
    if (ufs[x] < 0)
        return x;
    return ufsFind(ufs, ufs[x]);
}

int ufsUnion(vector<int>& ufs, int x, int y) {
    int rx = ufsFind(ufs, x);
    int ry = ufsFind(ufs, y);
    if (rx == ry)
        return -1;
    ufs[rx] += ufs[ry];
    ufs[ry] = rx;
    return ufs[rx];
}

int findCircleNum(vector<vector<int>>& isConnected, int n) {
    int res = 0;
    vector<int> ufs(n, -1);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (isConnected[i][j] == 1)
                ufsUnion(ufs, i, j);
        }
    }
    for (auto& v : ufs) {
        if (v < 0)
            res++;
    }
    return res;
}
BpointA commented 2 years ago

思路

并查集

代码

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        n=len(isConnected)
        visited=[0]*n
        def dfs(i):
            visited[i]=1
            for j in range(n):
                if isConnected[i][j]==1 and visited[j]==0:
                    dfs(j)
        c=0
        for i in range(n):
            if visited[i]==0:
                dfs(i)
                c+=1
        return c
QiZhongdd commented 2 years ago
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int provinces = isConnected.length;
        boolean[] visited = new boolean[provinces];
        int circles = 0;
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int i = 0; i < provinces; i++) {
            if (!visited[i]) {
                queue.offer(i);
                while (!queue.isEmpty()) {
                    int j = queue.poll();
                    visited[j] = true;
                    for (int k = 0; k < provinces; k++) {
                        if (isConnected[j][k] == 1 && !visited[k]) {
                            queue.offer(k);
                        }
                    }
                }
                circles++;
            }
        }
        return circles;
    }
}
zszs97 commented 2 years ago

开始刷题

题目简介

【Day 76 】2021-11-24 - 547. 省份数量

题目思路

题目代码

代码块

class Solution {
public:
    int Find(vector<int>& parent, int index) {
        if (parent[index] != index) {
            parent[index] = Find(parent, parent[index]);
        }
        return parent[index];
    }

    void Union(vector<int>& parent, int index1, int index2) {
        parent[Find(parent, index1)] = Find(parent, index2);
    }

    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 = i + 1; j < provinces; j++) {
                if (isConnected[i][j] == 1) {
                    Union(parent, i, j);
                }
            }
        }
        int circles = 0;
        for (int i = 0; i < provinces; i++) {
            if (parent[i] == i) {
                circles++;
            }
        }
        return circles;
    }
};

复杂度

Taylucky commented 2 years ago

思路 并查集 dfs python3 class Solution: def findCircleNum(self, isConnected: List[List[int]]) -> int: n=len(isConnected) visited=[0]*n def dfs(i): visited[i]=1 for j in range(n): if isConnected[i][j]==1 and visited[j]==0: dfs(j) c=0 for i in range(n): if visited[i]==0: dfs(i) c+=1 return c

nonevsnull commented 2 years ago

思路

AC

代码

class Solution {
    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        UF uf = new UF(n);

        for(int row = 0;row < n;row++){
            for(int col = row;col < n;col++){
                if(row == col) continue;
                if(isConnected[row][col] == 1)
                    uf.union(row, col);
            }
        }
        int count = 0;

        for(int weight: uf.weights){
            if(weight > 0)
                count++;
        }
        return count;
    }

    private class UF{
        int[] p, weights;

        public UF(int N){
            p = new int[N];

            for(int i = 0;i < N;i++){
                p[i] = i;
            }

            weights = new int[N];

            Arrays.fill(weights, 1);
        }

        public int find(int a){
            if(p[a] != a){
                p[a] = find(p[a]);
            }

            return p[a];
        }

        public boolean connected(int a, int b){
            return find(a) == find(b);
        }

        public void union(int a, int b){
            int pa = find(a);
            int pb = find(b);
            if(pa != pb){
                p[pa] = pb;

                weights[pb] += weights[pa];
                weights[pa] = 0;
            }

        }
    }
}

复杂度

time: N为矩阵大小,O(NlogN) space: O(N);

mannnn6 commented 2 years ago

代码

class Solution {
    public int findCircleNum(int[][] isConnected) {
        int provinces = isConnected.length;
        int[] parent = new int[provinces];
        for (int i = 0; i < provinces; i++) {
            parent[i] = i;
        }
        for (int i = 0; i < provinces; i++) {
            for (int j = i + 1; j < provinces; j++) {
                if (isConnected[i][j] == 1) {
                    union(parent, i, j);
                }
            }
        }
        int circles = 0;
        for (int i = 0; i < provinces; i++) {
            if (parent[i] == i) {
                circles++;
            }
        }
        return circles;
    }

    public void union(int[] parent, int index1, int index2) {
        parent[find(parent, index1)] = find(parent, index2);
    }

    public int find(int[] parent, int index) {
        if (parent[index] != index) {
            parent[index] = find(parent, parent[index]);
        }
        return parent[index];
    }
}

复杂度

时间复杂度:O(N^2*LogN) 空间复杂度:O(N)

ymkymk commented 2 years ago

class Solution { public int findCircleNum(int[][] isConnected) { int provinces = isConnected.length; boolean[] visited = new boolean[provinces]; int circles = 0; for (int i = 0; i < provinces; i++) { if (!visited[i]) { dfs(isConnected, visited, provinces, i); circles++; } } return circles; }

public void dfs(int[][] isConnected, boolean[] visited, int provinces, int i) {
    for (int j = 0; j < provinces; j++) {
        if (isConnected[i][j] == 1 && !visited[j]) {
            visited[j] = true;
            dfs(isConnected, visited, provinces, j);
        }
    }
}

}

Zhang6260 commented 2 years ago

JAVA版本

思路:

该题可以通过暴力法和使用前缀树的方式(暴力法则是使用深度优先搜索或者广度优先搜索)

class Solution {
    public int findCircleNum(int[][] isConnected) {
        if(isConnected==null||isConnected.length==0)return 0;
        int si=isConnected.length;
        UnidFind uf=new UnidFind(si);
        for(int i=0;i<si;i++){
            for(int j=0;j<si;j++){
                if(isConnected[i][j]==1)uf.union(i,j);
            }
        }
        return uf.count;
    }
    private class UnidFind{
        int count;
        int[]partent;
        int[]size;
        UnidFind(int n){
            count=n;
            partent=new int[n];
            size=new int[n];
            Arrays.fill(size,1);
            for(int i=0;i<n;i++)partent[i]=i;
        }
        public int findset(int i){
            if(partent[i]!=i)partent[i]=findset(partent[i]);
            return partent[i];
        }
        public void union(int x,int y){
            int x1=findset(x);
            int y1=findset(y);
            if(x1!=y1){
                if(size[x1]>size[y1]){
                    partent[y1]=x1;
                }else if(size[x1]<size[y1]){
                    partent[x1]=y1;
                }else{
                    partent[y1]=x1;
                    size[y1]++;
                }
                --count;
            }
        }
        public int getcount(){
            return count;
        }
    }
}

时间复杂度:O(nlogn)

空间复杂度:O(n)

carinSkyrim commented 2 years ago

代码

class UnionFind:
    def __init__(self):
        self.father = {}
        # 额外记录集合的数量
        self.num_of_sets = 0

    def find(self,x):
        root = x

        while self.father[root] != None:
            root = self.father[root]

        while x != root:
            original_father = self.father[x]
            self.father[x] = root
            x = original_father

        return root

    def merge(self,x,y):
        root_x,root_y = self.find(x),self.find(y)

        if root_x != root_y:
            self.father[root_x] = root_y
            # 集合的数量-1
            self.num_of_sets -= 1

    def add(self,x):
        if x not in self.father:
            self.father[x] = None
            # 集合的数量+1
            self.num_of_sets += 1

class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        uf = UnionFind()
        for i in range(len(M)):
            uf.add(i)
            for j in range(i):
                if M[i][j]:
                    uf.merge(i,j)

        return uf.num_of_sets
guangsizhongbin commented 2 years ago
func findCircleNum(isConnected [][]int) (ans int) {
    n := len(isConnected)
    parent := make([]int, n)
    for i := range parent {
        parent[i] = i
    }

    var find func(int) int
    find = func(x int) int {
        if parent[x] != x {
            parent[x] = find(parent[x])
        }
        return parent[x]
    }
    union := func(form, to int){
        parent[find(form)] = find(to)
    }

    for i, row := range isConnected{
        for j := i + 1; j < n ; j++{
            if row[j] == 1{
                union(i, j)
            }
        }
    }
    for i, p := range parent {
        if i == p {
            ans ++
        }
    }
    return ans
}
brainlds commented 2 years ago

class Solution { public int findCircleNum(int[][] isConnected) { int provinces = isConnected.length; boolean[] visited = new boolean[provinces]; int circles = 0; for (int i = 0; i < provinces; i++) { if (!visited[i]) { dfs(isConnected, visited, provinces, i); circles++; } } return circles; }

public void dfs(int[][] isConnected, boolean[] visited, int provinces, int i) {
    for (int j = 0; j < provinces; j++) {
        if (isConnected[i][j] == 1 && !visited[j]) {
            visited[j] = true;
            dfs(isConnected, visited, provinces, j);
        }
    }
}

}

yj9676 commented 2 years ago
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int provinces = isConnected.length;
        int[] parent = new int[provinces];
        for (int i = 0; i < provinces; i++) {
            parent[i] = i;
        }
        for (int i = 0; i < provinces; i++) {
            for (int j = i + 1; j < provinces; j++) {
                if (isConnected[i][j] == 1) {
                    union(parent, i, j);
                }
            }
        }
        int circles = 0;
        for (int i = 0; i < provinces; i++) {
            if (parent[i] == i) {
                circles++;
            }
        }
        return circles;
    }

    public void union(int[] parent, int index1, int index2) {
        parent[find(parent, index1)] = find(parent, index2);
    }

    public int find(int[] parent, int index) {
        if (parent[index] != index) {
            parent[index] = find(parent, parent[index]);
        }
        return parent[index];
    }
}
chaggle commented 2 years ago

title: "Day 76 547. 省份数量" date: 2021-11-24T21:42:41+08:00 tags: ["Leetcode", "c++", "UnionFind"] categories: ["91-day-algorithm"] draft: true


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]

题目思路

  • 1、刚好考研今年也新增并查集的学习,所以本次刚好可以复习一下UnionFind class 的相应的写法。
class UnionFind {
private:
    unordered_map<int, int> data; //存储父节点

    int cnt = 0; //记录数目

public:
    int find(int x) {
        int root = x;

        while(data[root] >= 0) root = data[root];

        //路径压缩
        while(x != root) {
            int tmp = data[x]; //tmp 指向 x 的父节点
            data[x] = root;    //挂到根节点下
            x = tmp;
        }

        return root; //返回根节点的编号。
    }

    bool isconnected(int x, int y) {
        return find(x) == find(y);
    }

    void merge(int x, int y) {
        int p = find(x);
        int q = find(y);

        if(p != q) {
            data[p] = q;
            cnt--;
        }
    }

    void add(int x) {
        if(data.count(x) == 0) {
            data[x] = -1;
            cnt++;
        }
    }

    int getCnt() {
        return cnt;
    }
};

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        UnionFind u;
        int n = isConnected.size();
        for (int i = 0; i < n; i++) {
            u.add(i);
            for(int j = 0; j < i; j++) {
                if(isConnected[i][j]) u.merge(i, j);
            }
        }
        return u.getCnt();
    }
};

复杂度

wangyifan2018 commented 2 years ago
class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        def find(index: int) -> int:
            if parent[index] != index:
                parent[index] = find(parent[index])
            return parent[index]

        def union(index1: int, index2: int):
            parent[find(index1)] = find(index2)

        provinces = len(isConnected)
        parent = list(range(provinces))

        for i in range(provinces):
            for j in range(i + 1, provinces):
                if isConnected[i][j] == 1:
                    union(i, j)

        circles = sum(parent[i] == i for i in range(provinces))
        return circles
revisegoal commented 2 years ago

思路

UF模板

代码

class Solution {
    class UF {
        int[] parent;
        int[] size;
        int cnt;

        UF(int n) {
            parent = new int[n];
            size = new int[n];
            cnt = n;
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
            }
        }

        int find(int node) {
            if (parent[node] != node) {
                parent[node] = find(parent[node]);
                return parent[node];
            }
            return node;
        }

        void union(int p, int q) {
            if (connected(p, q)) {
                return;
            }
            if (size[find(p)] < size[find(q)]) {
                parent[find(p)] = find(q);
                size[find(q)] = size[find(q)] + 1;
            } else {
                parent[find(q)] = find(p);
                size[find(p)] = size[find(p)] + 1;
            }
            cnt--;
        }

        boolean connected(int p, int q) {
            return find(p) == find(q);
        }
    }

    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (isConnected[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }
        return uf.cnt;
    }

}

复杂度

ChenJingjing85 commented 2 years ago

思路

并查集,求连通域个数

代码

class Solution:
    def find(self, x): #找x的祖先
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x]) #路径压缩
        return self.parent[x] #这边要返回self.parent[x], 这样每一层递归返回时,都是返回的这一个祖先,这样每次在递归调用处self.parent[x] =赋值时才一直赋值的是这一个祖先

    def connected(self, i, j):
        return self.find(i) == self.find(j)

    def union(self, i, j): #将i的祖先挂到j的祖先下面
        if self.connected(i, j): return
        ancestor_i = self.find(i)
        ancestor_j = self.find(j)
        if self.size[ancestor_i] > self.size[ancestor_j]:
            self.parent[ancestor_j] = ancestor_i
            self.size[ancestor_i] += self.size[ancestor_j]
        else:
            self.parent[ancestor_i] = ancestor_j
            self.size[ancestor_j] += self.size[ancestor_i]        
        self.cnt -= 1

    def findCircleNum(self, isConnected: List[List[int]]) -> int:
         #先初始化UF,所有城市独立
        n = len(isConnected)
        self.parent = {}
        self.size = {}
        self.cnt = 0
        for i in range(n):
            self.parent[i] = i
            self.size[i] = 1
            self.cnt += 1
        # i->j =1, 则将i的祖先合并到j的祖先,连通域-1

        for i in range(n-1):
            for j in range(i+1, n):
                if isConnected[i][j] == 1:
                    self.union(i, j)
        return self.cnt

复杂度

V-Enzo commented 2 years ago

思路

  1. 求连通图。在这里使用并查集来解决这个问题。
  2. 重点在两个点之间有边,但是父节点不相等,那么就要给它们的父节点置为相等,认为是联通的。
  3. 联通了过后需要计数器减一。

    class Solution {
    vector<int> p;
    public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int N =isConnected.size();
        for(int i=0; i<N; i++)
        {
            p.push_back(i);
        }
        int count = N;
        for(int i=0; i<N; i++)
        {
            for(int j=0; j<isConnected[0].size(); j++)
            {
                if(isConnected[i][j]==1 && findx(i) != findx(j))
                {
                    p[findx(i)] = findx(j);
                    count--;
                }
            }
        }
        return count;
    }
    int findx(int x)
    {
        if(p[x]!=x)
            p[x] = findx(p[x]);
        return p[x];
    
    }
    };

    Complexity:

    Time:O(1) Space:O(n)

yingliucreates commented 2 years ago

link:

https://leetcode.com/problems/number-of-provinces/

代码 Javascript

const findCircleNum = function(isConnected) {
    let visited = new Set, provs = 0;
    for(let i = 0; i < isConnected.length; i++) {
        if(!(visited.has(i))) {
           provs++;
           DFS(isConnected, i, visited);
        }
    }
    return provs;
};

const DFS = (isConnected, i, visited) => {
    visited.add(i);
    for(let j = 1; j < isConnected.length; j++) {
        if(isConnected[i][j] && !(visited.has(j))) {
            DFS(isConnected, j, visited);
        }
    }
}
shamworld commented 2 years ago
var findCircleNum = function(isConnected) {
    let n = isConnected.length;
    if (n==0) return 0;
    let visited = {};
    let count = 0;
    let dfs = (i)=>{
        for(let j=0;j<n;j++){
            if(isConnected[i][j]==1&&!visited[j]){
                visited[j] = true;
                dfs(j);
            }
        }
    }
    for(let i=0;i<n;i++){
        if(!visited[i]){
            dfs(i);
            count++;
        }
    }
    return count;
};
falsity commented 2 years ago
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int provinces = isConnected.length;
        int[] parent = new int[provinces];
        for (int i = 0; i < provinces; i++) {
            parent[i] = i;
        }
        for (int i = 0; i < provinces; i++) {
            for (int j = i + 1; j < provinces; j++) {
                if (isConnected[i][j] == 1) {
                    union(parent, i, j);
                }
            }
        }
        int circles = 0;
        for (int i = 0; i < provinces; i++) {
            if (parent[i] == i) {
                circles++;
            }
        }
        return circles;
    }

    public void union(int[] parent, int index1, int index2) {
        parent[find(parent, index1)] = find(parent, index2);
    }

    public int find(int[] parent, int index) {
        if (parent[index] != index) {
            parent[index] = find(parent, parent[index]);
        }
        return parent[index];
    }
}
yibenxiao commented 2 years ago

【Day 76】547. 省份数量

思路

DFS

代码

class Solution {
public:
    void DFS(int i,int len, vector<vector<int>>& isConnected, vector<int>& visited)
    {
        for (int j = 0; j < len; ++j)
        {
            if (i != j && !visited[j] && isConnected[i][j])
            {
                visited[j] = 1;
                DFS(j, len, isConnected, visited);
            }
        }
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        int len = isConnected.size();
        vector<int>visited(len, 0);
        int res = 0;
        for (int i = 0; i < len; ++i)
        {
            if (!visited[i])
            {
                visited[i] = 1;
                DFS(i, len, isConnected, visited);
                ++res;
            }
        }
        return res;
    }

};

复杂度

时间复杂度:O(N)

空间复杂度:O(N)

user1689 commented 2 years ago

题目

https://leetcode-cn.com/problems/number-of-provinces/

思路

DFS/BFS/UnionFind

python3

class UnionFind:
    def __init__(self):
        self.father = {}
        # 额外记录集合的数量
        self.num_of_sets = 0

    def find(self,x):
        root = x

        while self.father[root] != None:
            root = self.father[root]

        while x != root:
            original_father = self.father[x]
            self.father[x] = root
            x = original_father

        return root

    def merge(self,x,y):
        root_x,root_y = self.find(x),self.find(y)

        if root_x != root_y:
            self.father[root_x] = root_y
            # 集合的数量-1
            self.num_of_sets -= 1

    def add(self,x):
        if x not in self.father:
            self.father[x] = None
            # 集合的数量+1
            self.num_of_sets += 1

class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        uf = UnionFind()
        for i in range(len(M)):
            uf.add(i)
            for j in range(i):
                if M[i][j]:
                    uf.merge(i,j)

        return uf.num_of_sets

复杂度分析

相关题目

  1. https://leetcode-cn.com/problems/redundant-connection/
  2. 待补充(连通性问题)
last-Battle commented 2 years ago

代码

C++ Code:


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]) {
                visited[j] = 1;
                dfs(isConnected, visited, provinces, j);
            }
        }
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        int provinces = isConnected.size();
        vector<int> visited(provinces);
        int circles = 0;
        for (int i = 0; i < provinces; i++) {
            if (!visited[i]) {
                dfs(isConnected, visited, provinces, i);
                circles++;
            }
        }
        return circles;
    }
};

复杂度分析

令 n 为数组长度。

BreezePython commented 2 years ago

思路

深度优先搜索

代码

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        def dfs(i: int):
            for j in range(provinces):
                if isConnected[i][j] == 1 and j not in visited:
                    visited.add(j)
                    dfs(j)

        provinces = len(isConnected)
        visited = set()
        circles = 0

        for i in range(provinces):
            if i not in visited:
                dfs(i)
                circles += 1

        return circles

复杂度

taojin1992 commented 2 years ago
# Understand:
1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j] is 1 or 0.
isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]

# Tests:

Input: isConnected = 
[[1,1,0],
 [1,1,0],
 [0,0,1]]

Output: 2,[1,2],[3]

isConnected = [[1,0,0],[0,1,0],[0,0,1]]
3

[1,0,1],
[0,1,1],
[1,1,1]

return 1

1-3
  |
  2

Method 1: union find

union with path compression by rank
if isConnected[i][j] == 1, union(i, j)

return numOfUnions

Time: O(n^2)
Space: O(n), n = isConnected.length

Method 2: DFS

start from each node ([0, n-1]) by a for loop, 
- if visited, continue
- if unvisited, mark as visited, explore as many as possible by dfs, increment the count

Time:
O(V + E), V = isConnected.length, E = number of edges = number of 1's in isConnected

E is bounded by n^2
O(n^2)

Space:
stack + visited array
O(V) + O(V)
= O(isConnected.length)

Method 3: BFS

use BFS to start from each node, explore as much as possible, only explore unvisited node

Time: O(V + E) = O(n + n ^ 2) = O(n ^ 2)
Space: O(V) = O(n)

Code:

class Solution {
    // method 3: BFS
    public int findCircleNum(int[][] isConnected) {
        Queue<Integer> nodeQueue = new LinkedList<>();
        int circleNum = 0;
        int n = isConnected.length;
        boolean[] visited = new boolean[n];
        for (int start = 0; start < n; start++) {
            if (!visited[start]) {
                nodeQueue.offer(start);
                /*
                while (!nodeQueue.isEmpty()) {
                    int size = nodeQueue.size();
                    for (int i = 0; i < size; i++) {
                        int curNode = nodeQueue.poll();
                        visited[curNode] = true;
                        for (int next = 0; next < isConnected[0].length; next++) {
                            if (isConnected[curNode][next] == 1 && !visited[next]) {
                                nodeQueue.offer(next);
                            }
                        }
                    }     
                }*/
                // optimized, no need for the size inner loop
                while (!nodeQueue.isEmpty()) {
                    int curNode = nodeQueue.poll();
                    visited[curNode] = true;
                    for (int next = 0; next < isConnected[0].length; next++) {
                        if (isConnected[curNode][next] == 1 && !visited[next]) {
                            nodeQueue.offer(next);
                        }
                    }
                }     
                circleNum++;
            }
        }
        return circleNum;
    }

    // method 2: DFS, need review!  
    public int findCircleNum2(int[][] isConnected) {
        int n = isConnected.length;
        boolean[] visited = new boolean[n];
        int circleNum = 0;
        for (int start = 0; start < n; start++) {
            if (!visited[start]) {
                dfs(start, isConnected, visited);
                // each dfs finishes covering as many as nodes
                circleNum++;
            }
        }
        return circleNum;
    }

    private void dfs(int curNode, int[][] isConnected, boolean[] visited) {
        visited[curNode] = true;
        for (int next = 0; next < isConnected[0].length; next++) {
            // second condition guarantees next != cur
            if (isConnected[curNode][next] == 1 && !visited[next]) {
                dfs(next, isConnected, visited);
            }
        }
    }

    // method 1: Union Find
    class UF {
        int numOfUnions;
        int[] size;
        int[] parent;

        UF(int n) {
            numOfUnions = n;
            size = new int[n];
            parent = new int[n];
            for (int i = 0; i < n; i++) {
                size[i] = 1;
                parent[i] = i;
            }
        }

        boolean isConnected(int p, int q) {
            return find(p) == find(q);
        }

        int find(int x) {
            while (parent[x] != x) {
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }

        void union(int p, int q) {
            int representativeOfP = find(p);
            int representativeOfQ = find(q);
            if (representativeOfP == representativeOfQ) {
                return;
            }
            if (size[representativeOfP] < size[representativeOfQ]) {
                size[representativeOfQ] += size[representativeOfP];
                parent[representativeOfP] = representativeOfQ;
            } else {
                size[representativeOfP] += size[representativeOfQ];
                parent[representativeOfQ] = representativeOfP;
            }
            numOfUnions--;
        }
    }

    public int findCircleNum1(int[][] isConnected) {
        int n = isConnected.length;
        UF unionfind = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                if (isConnected[i][j] == 1) {
                    unionfind.union(i, j);
                }
            }
        }
        return unionfind.numOfUnions;
    }
}
qixuan-code commented 2 years ago
class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        provinces = len(isConnected)
        visited = set()
        circles = 0

        for i in range(provinces):
            if i not in visited:
                Q = collections.deque([i])
                while Q:
                    j = Q.popleft()
                    visited.add(j)
                    for k in range(provinces):
                        if isConnected[j][k] == 1 and k not in visited:
                            Q.append(k)
                circles += 1

        return circles
ZETAVI commented 2 years ago
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (isConnected[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }
        return uf.size;
    }
    private static class UF {
        int[] parent;
        int size;
        public UF(int n) {
            parent = new int[n];
            size = n;
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }
        public int find(int x) {
            while (parent[x] != x) {
                x = parent[x];
            }
            return x;
        }
        public void union(int x, int y) {
            if (find(x) != find(y)) {
                parent[find(x)] = find(y);
                size--;
            }
        }
    }
}
lihuiwen commented 2 years ago

代码

const findCircleNum = function(isConnected) {
    let visited = new Set, provs = 0;
    for(let i = 0; i < isConnected.length; i++) {
        if(!(visited.has(i))) {
           provs++;
           DFS(isConnected, i, visited);
        }
    }
    return provs;
};

const DFS = (isConnected, i, visited) => {
    visited.add(i);
    for(let j = 1; j < isConnected.length; j++) {
        if(isConnected[i][j] && !(visited.has(j))) {
            DFS(isConnected, j, visited);
        }
    }
}