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

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

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

返回矩阵中 省份 的数量。

示例 1:

省份数量-547 - 图1

  1. Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]]
  2. Output: 2

示例 2:

省份数量-547 - 图2

  1. Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]]
  2. Output: 3

提示:

  • 1 ≤ n ≤ 200;
  • n == isConnected.length
  • n == isConnected[i].length
  • isConnected[i][i] == 1
  • isConnected[i][j] == isConnected[j][i]

思路

并查集(Disjoint Set)是用于判断一个图里有没有环的,对于知识点的讲解推荐正月点灯笼的视频。

题目以邻接矩阵的形式给出了图,该矩阵是方阵。我们为图创建一个并查集:

  • 新建一个int parent[ isConnected.size() ]数组,长度和矩阵的边长一样;
  • parent的每个元素赋值为自己本身,比如parent[0] = 0parent[1] = 1;意味着该点的父节点是它自己;
  • 编写find_root()方法,用于查找某个节点的父节点;
  • 编写union_find()方法,用于将两个点的父子关系;
  • 最后遍历一遍parent数组,当parent[i] == i时,省份数目加一;

代码

  1. class Solution {
  2. public:
  3. int findCircleNum(vector<vector<int>>& isConnected) {
  4. if( isConnected.size() == 1 ) return 1;
  5. // Create a parent array
  6. vector<int> parent( isConnected.size() );
  7. for(int i = 0; i < isConnected.size(); i++) {
  8. parent[i] = i; // parent is itself
  9. }
  10. // Union all the nodes
  11. for(int i = 1; i < isConnected.size(); i++) {
  12. for(int j = 0; j < i; j++) {
  13. if( isConnected[i][j] == 1 ) {
  14. union_find(i, j, parent);
  15. }
  16. }
  17. }
  18. // Walk the parent and find the provience
  19. unsigned counter = 0;
  20. for(int i = 0; i < parent.size(); i++) {
  21. if( parent[i] == i )
  22. counter++;
  23. }
  24. return counter;
  25. }
  26. int find_root(int node, const vector<int>& parent) {
  27. while( parent[node] != node ) {
  28. node = parent[ node ];
  29. }
  30. return node;
  31. }
  32. void union_find(int node_a, int node_b, vector<int>& parent) {
  33. int a_root = find_root(node_a, parent);
  34. int b_root = find_root(node_b, parent);
  35. parent[a_root] = b_root;
  36. }
  37. };