547. 省份数量

题目来源:LeetCode 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]

并查集解法

使用quick find

class UnionFind {
  constructor(len) {
    this.root = Array(len).fill(0).map((_, i) => i);
  }
  find(x) {
    return this.root[x];
  }
  union(x, y) {
    let rootx = this.find(x), rooty = this.find(y);
    if(rootx !== rooty) {
      for(let i = 0;i<this.root.length;i++) {
        if(this.root[i] === rootx) this.root[i] = rooty;
      }
    }
  }
  getNums() {
    return new Set(this.root).size;
  }
}

var findCircleNum = function(isConnected) {
    // quick find
    const uf = new UnionFind(isConnected.length);
    for(const [i, vals] of isConnected.entries()) {
        for(const [j, val] of vals.entries()) {
            if(val === 1) uf.union(i, j);
        }
    }
    return uf.getNums();
};

基于路径压缩的按秩合并优化的「并查集」

class UnionFind {
  constructor(len) {
    this.root = Array(len)
      .fill(0)
      .map((_, i) => i);
    this.rank = Array(len).fill(1);
    this.size = len;
  }
  // 路径压缩优化版本的 find 函数
  find(x) {
    if (x === this.root[x])  return x;
    return this.root[x] = this.find(this.root[x]);
  }
  // 按秩合并优化的 union 函数
  union(x, y) {
    let rootx = this.find(x), rooty = this.find(y);
    if(rootx !== rooty) {
      if(this.rank[rootx] > this.rank[rooty]) {
        this.root[rooty] = rootx;
      } else if(this.rank[rootx] < this.rank[rooty]) {
        this.root[rootx] = rooty;
      } else { // ===
        this.root[rootx] = rooty;
        this.rank[rooty] += 1;
      }
      this.size--;
    }
  }
}

var findCircleNum = function(isConnected) {
    const n = isConnected.length;
    const uf = new UnionFind(n);
    for(let i = 0;i<n;i++) {
        for(let j = 0;j<isConnected[i].length;j++) {
            if(isConnected[i][j] === 1) uf.union(i, j);
        }
    }
    return uf.size;
};

DFS解法

/**
 * @param {number[][]} isConnected
 * @return {number}
 */
var findCircleNum = function(isConnected) {
    let visited = new Set(),re = 0;
    for(let i = 0;i<isConnected.length;i++){
        if(!visited.has(i)){
            dfs(isConnected,visited,i);
            re++;
        }
    }
    return re;
};
function dfs(data,visited,i){
    for(let j = 0;j<data.length;j++){
        if(data[i][j] === 1 && !visited.has(j)){
            visited.add(j);
            dfs(data,visited,j);
        }
    }
}
0%