@@ -40,6 +40,7 @@ impl UnionFind {
40
40
}
41
41
root
42
42
}
43
+
43
44
pub fn is_connected ( & self , p : usize , q : usize ) -> bool {
44
45
self . find ( p) == self . find ( q)
45
46
}
@@ -74,7 +75,7 @@ pub fn find_circle_num(is_connected: Vec<Vec<i32>>) -> i32 {
74
75
75
76
/// [684. 冗余连接](https://leetcode.cn/problems/redundant-connection/)
76
77
pub fn find_redundant_connection ( edges : Vec < Vec < i32 > > ) -> Vec < i32 > {
77
- let mut uf = UnionFind :: new ( edges. len ( ) + 1 ) ;
78
+ let mut uf = UnionFind :: new ( edges. len ( ) + 1 ) ;
78
79
let mut curr_count = uf. count ( ) ;
79
80
let mut last_edge = vec ! [ ] ;
80
81
@@ -90,11 +91,206 @@ pub fn find_redundant_connection(edges: Vec<Vec<i32>>) -> Vec<i32> {
90
91
last_edge
91
92
}
92
93
94
+ /// [990. 等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/)
95
+ pub fn equations_possible ( equations : Vec < String > ) -> bool {
96
+ let mut uf = UnionFind :: new ( 26 ) ;
97
+
98
+ let mut not_equal = vec ! [ ] ; // 暂存
99
+
100
+ for e in equations {
101
+ let s = e. as_bytes ( ) ;
102
+ let ( a, b, eq) = ( s[ 0 ] - b'a' , s[ 3 ] - b'a' , s[ 1 ] == b'=' ) ;
103
+ if eq {
104
+ uf. connect ( a as usize , b as usize ) ;
105
+ } else {
106
+ not_equal. push ( ( a as usize , b as usize ) ) ;
107
+ }
108
+ }
109
+
110
+ for ( a, b) in not_equal {
111
+ if uf. is_connected ( a, b) {
112
+ return false ;
113
+ }
114
+ }
115
+ true
116
+ }
117
+
118
+ /// [839. 相似字符串组](https://leetcode.cn/problems/similar-string-groups/)
119
+ pub fn num_similar_groups ( strs : Vec < String > ) -> i32 {
120
+ fn is_similar ( s1 : & str , s2 : & str ) -> bool {
121
+ s1. chars ( ) . zip ( s2. chars ( ) ) . filter ( |( a, b) | !a. eq ( b) ) . count ( ) <= 2
122
+ }
123
+ let mut uf = UnionFind :: new ( strs. len ( ) ) ;
124
+
125
+ for i in 0 ..strs. len ( ) {
126
+ let s1 = strs. get ( i) . unwrap ( ) ;
127
+ for j in i + 1 ..strs. len ( ) {
128
+ if uf. is_connected ( i, j) {
129
+ continue ;
130
+ }
131
+
132
+ let s2 = strs. get ( j) . unwrap ( ) ;
133
+ if is_similar ( s1, s2) {
134
+ uf. connect ( i, j) ;
135
+ }
136
+ }
137
+ }
138
+ uf. count ( ) as i32
139
+ }
140
+
141
+ /// [841. 钥匙和房间](https://leetcode.cn/problems/keys-and-rooms/)
142
+ ///
143
+ /// 关键信息: 除 `0` 号房间外的其余所有房间都被锁住
144
+ ///
145
+ /// 解法1: bfs
146
+ /// ```
147
+ /// pub fn can_visit_all_rooms(rooms: Vec<Vec<i32>>) -> bool {
148
+ /// use std::collections::HashSet;
149
+ /// use std::collections::VecDeque;
150
+ ///
151
+ /// let mut queue = VecDeque::new();
152
+ /// let mut visited = HashSet::new();
153
+ ///
154
+ /// queue.push_back(0);
155
+ /// visited.insert(0);
156
+ /// while let Some(n) = queue.pop_front() {
157
+ /// let room = rooms.get(n).unwrap();
158
+ /// for &r in room.iter(){
159
+ /// if !visited.insert(r) {
160
+ /// continue;
161
+ /// }
162
+ /// queue.push_back(r as usize)
163
+ /// }
164
+ /// }
165
+ /// visited.len() == rooms.len()
166
+ /// }
167
+ /// ```
168
+ ///
169
+ /// 解法二: 并查集
170
+ ///
171
+ /// 由于 `HashSet` 这里也只是用了 `insert` 和 `contain` 两个方法, 因此换成 并查集判定也是OK的.
172
+ /// 甚至内存表现上, 并查集更优.
173
+ pub fn can_visit_all_rooms ( rooms : Vec < Vec < i32 > > ) -> bool {
174
+ use std:: collections:: VecDeque ;
175
+ let mut uf = UnionFind :: new ( rooms. len ( ) ) ;
176
+
177
+ let mut queue = VecDeque :: new ( ) ;
178
+
179
+ queue. push_back ( 0 ) ;
180
+ while let Some ( curr) = queue. pop_front ( ) {
181
+ let room = rooms. get ( curr) . unwrap ( ) ;
182
+ for & r in room. iter ( ) {
183
+ if uf. is_connected ( curr, r as usize ) {
184
+ continue ;
185
+ }
186
+ uf. connect ( curr, r as usize ) ;
187
+ queue. push_back ( r as usize ) ;
188
+ }
189
+ }
190
+ uf. count ( ) == 1
191
+ }
192
+
93
193
#[ cfg( test) ]
94
194
mod test {
95
195
use super :: * ;
96
196
use crate :: vec2;
97
197
198
+ #[ test]
199
+ fn test_can_visit_all_rooms ( ) {
200
+ struct Testcase {
201
+ rooms : Vec < Vec < i32 > > ,
202
+ expect : bool ,
203
+ }
204
+
205
+ vec ! [
206
+ Testcase {
207
+ rooms: vec2![ [ 1 ] , [ 2 ] , [ 3 ] , [ ] ] ,
208
+ expect: true ,
209
+ } ,
210
+ Testcase {
211
+ rooms: vec2![ [ 1 , 3 ] , [ 3 , 0 , 1 ] , [ 2 ] , [ 0 ] ] ,
212
+ expect: false ,
213
+ } ,
214
+ Testcase {
215
+ rooms: vec2![ [ 1 ] , [ ] , [ 0 , 3 ] , [ 1 ] ] ,
216
+ expect: false ,
217
+ } ,
218
+ ]
219
+ . into_iter ( )
220
+ . enumerate ( )
221
+ . for_each ( |( idx, testcase) | {
222
+ let Testcase { rooms, expect } = testcase;
223
+ let actual = can_visit_all_rooms ( rooms) ;
224
+ assert_eq ! ( expect, actual, "case {} failed" , idx) ;
225
+ } ) ;
226
+ }
227
+
228
+ #[ test]
229
+ fn test_num_similar_groups ( ) {
230
+ struct TestCase {
231
+ strs : Vec < & ' static str > ,
232
+ expect : i32 ,
233
+ }
234
+
235
+ vec ! [
236
+ TestCase {
237
+ strs: vec![ "tars" , "rats" , "arts" , "star" ] ,
238
+ expect: 2 ,
239
+ } ,
240
+ TestCase {
241
+ strs: vec![ "omv" , "ovm" ] ,
242
+ expect: 1 ,
243
+ } ,
244
+ ]
245
+ . into_iter ( )
246
+ . enumerate ( )
247
+ . for_each ( |( idx, testcase) | {
248
+ let TestCase { strs, expect } = testcase;
249
+ let strs = strs. into_iter ( ) . map ( str:: to_string) . collect ( ) ;
250
+ let actual = num_similar_groups ( strs) ;
251
+ assert_eq ! ( expect, actual, "case {} failed" , idx) ;
252
+ } ) ;
253
+ }
254
+
255
+ #[ test]
256
+ fn test_equations_possible ( ) {
257
+ struct TestCase {
258
+ equations : Vec < & ' static str > ,
259
+ expect : bool ,
260
+ }
261
+
262
+ vec ! [
263
+ TestCase {
264
+ equations: vec![ "a==b" , "b!=a" ] ,
265
+ expect: false ,
266
+ } ,
267
+ TestCase {
268
+ equations: vec![ "b==a" , "a==b" ] ,
269
+ expect: true ,
270
+ } ,
271
+ TestCase {
272
+ equations: vec![ "a==b" , "b==c" , "a==c" ] ,
273
+ expect: true ,
274
+ } ,
275
+ TestCase {
276
+ equations: vec![ "a==b" , "b!=c" , "c==a" ] ,
277
+ expect: false ,
278
+ } ,
279
+ TestCase {
280
+ equations: vec![ "c==c" , "b==d" , "x!=z" ] ,
281
+ expect: true ,
282
+ } ,
283
+ ]
284
+ . into_iter ( )
285
+ . enumerate ( )
286
+ . for_each ( |( idx, testcase) | {
287
+ let TestCase { equations, expect } = testcase;
288
+ let equations = equations. into_iter ( ) . map ( str:: to_string) . collect ( ) ;
289
+ let actual = equations_possible ( equations) ;
290
+ assert_eq ! ( expect, actual, "case {} failed" , idx) ;
291
+ } ) ;
292
+ }
293
+
98
294
#[ test]
99
295
fn test_find_redundant_connection ( ) {
100
296
struct Testcase {
0 commit comments