39
39
这里整理出我的并查集模板如下:
40
40
41
41
``` CPP
42
- int n = 1005 ; // 节点数量3 到 1000
43
- int father[ 1005 ];
42
+ int n = 1005 ; // n根据题目中节点数量而定,一般比节点数量大一点就好
43
+ vector< int > father = vector< int > (n, 0 ); // C++里的一种数组结构
44
44
45
45
// 并查集初始化
46
46
void init () {
@@ -50,40 +50,58 @@ void init() {
50
50
}
51
51
// 并查集里寻根的过程
52
52
int find (int u) {
53
- return u == father[ u] ? u : father[ u] = find(father[ u] );
54
- }
55
- // 将v->u 这条边加入并查集
56
- void join(int u, int v) {
57
- u = find(u);
58
- v = find(v);
59
- if (u == v) return ;
60
- father[ v] = u;
53
+ return u == father[ u] ? u : father[ u] = find(father[ u] ); // 路径压缩
61
54
}
55
+
62
56
// 判断 u 和 v是否找到同一个根
63
- bool same (int u, int v) {
57
+ bool isSame (int u, int v) {
64
58
u = find(u);
65
59
v = find(v);
66
60
return u == v;
67
61
}
62
+
63
+ // 将v->u 这条边加入并查集
64
+ void join(int u, int v) {
65
+ u = find(u); // 寻找u的根
66
+ v = find(v); // 寻找v的根
67
+ if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
68
+ father[ v] = u;
69
+ }
70
+
68
71
```
69
72
70
- 以上模板汇总, 只要修改 n 和father数组的大小就可以了 。
73
+ 以上模板 只要修改 n 就可以了,本题 节点数量不会超过1000 。
71
74
72
75
并查集主要有三个功能。
73
76
74
77
1. 寻找根节点,函数:find(int u),也就是判断这个节点的祖先节点是哪个
75
78
2. 将两个节点接入到同一个集合,函数:join(int u, int v),将两个节点连在同一个根节点上
76
- 3. 判断两个节点是否在同一个集合,函数:same (int u, int v),就是判断两个节点是不是同一个根节点
79
+ 3. 判断两个节点是否在同一个集合,函数:isSame (int u, int v),就是判断两个节点是不是同一个根节点
77
80
78
81
简单介绍并查集之后,我们再来看一下这道题目。
79
82
80
- 题目说是无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树。
83
+ 题目说是无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点) 。
81
84
82
85
如果有多个答案,则返回二维数组中最后出现的边。
83
86
84
- 那么我们就可以从前向后遍历每一条边,边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
87
+ 那么我们就可以从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
88
+
89
+ 如图所示:
90
+
91
+ 
92
+
93
+ 节点A 和节点 B 不在同一个集合,那么就可以将两个 节点连在一起。
85
94
86
- 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,如果再加入这条边一定就出现环了。
95
+
96
+ (如果题目中说:如果有多个答案,则返回二维数组中最前出现的边。 那我们就要 从后向前遍历每一条边了)
97
+
98
+ 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
99
+
100
+ 如图所示:
101
+
102
+ 
103
+
104
+ 已经判断 节点A 和 节点B 在在同一个集合(同一个根),如果将 节点A 和 节点B 连在一起就一定会出现环。
87
105
88
106
这个思路清晰之后,代码就很好写了。
89
107
@@ -93,7 +111,7 @@ bool same(int u, int v) {
93
111
class Solution {
94
112
private:
95
113
int n = 1005; // 节点数量3 到 1000
96
- int father[1005];
114
+ vector< int> father = vector<int> (n, 0); // C++里的一种数组结构
97
115
98
116
// 并查集初始化
99
117
void init() {
@@ -105,24 +123,22 @@ private:
105
123
int find(int u) {
106
124
return u == father[u] ? u : father[u] = find(father[u]);
107
125
}
108
- // 将v->u 这条边加入并查集
109
- void join(int u, int v) {
110
- u = find(u);
111
- v = find(v);
112
- if (u == v) return ;
113
- father[v] = u;
114
- }
115
- // 判断 u 和 v是否找到同一个根,本题用不上
116
- bool same(int u, int v) {
126
+ // 判断 u 和 v是否找到同一个根
127
+ bool isSame(int u, int v) {
117
128
u = find(u);
118
129
v = find(v);
119
130
return u == v;
120
131
}
132
+ // 将v->u 这条边加入并查集
133
+ void join(int u, int v) {
134
+ if (isSame(u, v)) return ;
135
+ father[v] = u;
136
+ }
121
137
public:
122
138
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
123
139
init();
124
140
for (int i = 0; i < edges.size(); i++) {
125
- if (same (edges[i][0], edges[i][1])) return edges[i];
141
+ if (isSame (edges[i][0], edges[i][1])) return edges[i];
126
142
else join(edges[i][0], edges[i][1]);
127
143
}
128
144
return {};
0 commit comments