微软面试题:LeetCode. 547. 省份数量 middle 出现次数:1 并查集
本文参考 Leetcode 547. 省份数量 题解区:https://leetcode-cn.com/problems/number-of-provinces/solution/python-duo-tu-xiang-jie-bing-cha-ji-by-m-vjdr/
一 . 并查集
基本概念
1. 并查集是一种数据结构;
2. 并查集这三个字,一个字代表一个意思 ;
3. 并(Union),代表合并 ;
4. 查(Find),代表查找 ;
5. 集(Set),代表这是一个以字典为基础的数据结构,它的基本功能是合并集合中的元素,查找集合中的元素;
6. 并查集的典型应用是有关连通分量的问题;
7. 并查集解决单个问题(添加,合并,查找)的时间复杂度都是O(1)O(1);
8. 因此,并查集可以应用到在线算法中;
并查集跟树有些类似,只不过它跟树是相反的。在树这个数据结构里面,每个节点会记录它的子节点。在并查集里,每个节点会记录它的父节点。
合并操作: 对两个节点 u 、 v ,先使用 Find 操作看是否在一个连通分量,若不在一个连通分量,假设 u 所在连通分量的节点数比 将 v 所
在连通分量的节点数多。将 v 的根结点 root_v 的父节点设为 u 的根结点 root_u。
查找操作:查找的过程中执行 路径压缩。
代码实现
1 //union find 算法 2 class UF 3 { 4 public: 5 // 构造一个并查集 6 UF(int n) 7 { 8 count = n; 9 parent.resize(n); 10 weight.resize(n); 11 for(int i = 0; i < n; i++) 12 { 13 parent[i] =i; 14 weight[i] = 1; 15 } 16 } 17 //并操作, 将节点p 和 节点 q 连通 18 void Union(int p, int q) 19 { 20 //查操作 21 int rootP = Find(p); 22 int rootQ = Find(q); 23 if(rootP == rootQ) 24 return; 25 //并操作 26 if(weight[rootP] > weight[rootQ]) 27 { 28 parent[rootQ] = rootP; 29 weight[rootP] += weight[rootQ]; 30 } 31 else 32 { 33 parent[rootP] = rootQ; 34 weight[rootQ] += rootP; 35 } 36 count--;//连通个数 -1 37 } 38 //查操作,查找 x 节点的根点 39 int Find(int x) 40 { 41 while(parent[x] != x) 42 { 43 //查找 x 根节点的同时,对树进行路径压缩 44 parent[x] = parent[parent[x]]; 45 x = parent[x]; 46 } 47 return x; 48 } 49 //判断节点p 和 节点 q 是否连通 50 bool isConnected(int p, int q) 51 { 52 int rootP = Find(p); 53 int rootQ = Find(q); 54 return rootP == rootQ; 55 } 56 //返回当前连通个数 57 int getCount() 58 { 59 return count; 60 } 61 private: 62 int count;//连通分量的个数 63 vector<int> parent;//保存节点的父节点 64 vector<int> weight;//保存节点所在连通分量的重量(节点数) 65 };
二 . 省份数量
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 //union find 算法 5 class UF 6 { 7 public: 8 // 构造一个并查集 9 UF(int n) 10 { 11 count = n; 12 parent.resize(n); 13 weight.resize(n); 14 for(int i = 0; i < n; i++) 15 { 16 parent[i] =i; 17 weight[i] = 1; 18 } 19 } 20 //并操作, 将节点p 和 节点 q 连通 21 void Union(int p, int q) 22 { 23 //查操作 24 int rootP = Find(p); 25 int rootQ = Find(q); 26 if(rootP == rootQ) 27 return; 28 //并操作 29 if(weight[rootP] > weight[rootQ]) 30 { 31 parent[rootQ] = rootP; 32 weight[rootP] += weight[rootQ]; 33 } 34 else 35 { 36 parent[rootP] = rootQ; 37 weight[rootQ] += rootP; 38 } 39 count--;//连通个数 -1 40 } 41 //查操作,查找 x 节点的根点 42 int Find(int x) 43 { 44 while(parent[x] != x) 45 { 46 //查找 x 根节点的同时,对树进行路径压缩 47 parent[x] = parent[parent[x]]; 48 x = parent[x]; 49 } 50 return x; 51 } 52 //判断节点p 和 节点 q 是否连通 53 bool isConnected(int p, int q) 54 { 55 int rootP = Find(p); 56 int rootQ = Find(q); 57 return rootP == rootQ; 58 } 59 //返回当前连通个数 60 int getCount() 61 { 62 return count; 63 } 64 private: 65 int count;//连通分量的个数 66 vector<int> parent;//保存节点的父节点 67 vector<int> weight;//保存节点所在连通分量的重量(节点数) 68 }; 69 70 class Solution { 71 public: 72 int findCircleNum(vector<vector<int>>& M) 73 { 74 // specila case 75 if(M.size() == 0) 76 return 0; 77 const int n = M.size(); 78 UF uf(n);//创建一个并查集对象 79 for(int i = 0; i < n; i++) 80 { 81 for(int j = i+1; j < n; j++)//表示朋友圈的矩阵是对称的 82 { 83 if(M[i][j] == 1) 84 { 85 uf.Union(i,j); 86 } 87 } 88 } 89 return uf.getCount(); 90 } 91 };