1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
| struct Solution;
// @lc code=start
/// 并查集
struct UnionFindSet {
n: usize,
pa: Vec<usize>,
}
impl UnionFindSet {
pub fn new(n: usize) -> Self {
UnionFindSet {
n,
pa: (0..n).collect::<Vec<_>>(),
}
}
pub fn size(&self) -> usize {
self.n
}
pub fn find(&mut self, a: usize) -> usize {
//assert!(a < self.n);
if self.pa[a] == a {
return a;
}
let a_ = self.find(self.pa[a]);
self.pa[a] = a_; // 压缩
a_
}
pub fn union(&mut self, a: usize, b: usize) {
let a_ = self.find(a);
let b_ = self.find(b);
if a_ != b_ {
self.pa[a_] = b_;
self.n -= 1;
}
}
}
impl Solution {
/// ## 解题思路
/// - 并查集+hashmap
/// 1. 所有同行或同列的石头(节点)之间相当于存在一条边来表示之间存在关联;
/// 所有有关联的边将节点聚集成为一个连通图, 最后剩下的石头数等于连通图个数;
/// 2. 用并查集来记录各个节点是否在一个连通图中;
/// 3. 用两个hashmap, 分别记录出现的节点的行列下标是否出现;
/// 4. 顺序遍历所有节点, 如果行或列下标出现过, 则将节点id合并到并查集中;
/// 否则, 将行列坐标记录到hashmap中;
/// 5. 最后结果: 节点数n - 并查集大小
pub fn remove_stones(stones: Vec<Vec<i32>>) -> i32 {
let n = stones.len();
let mut ufs = UnionFindSet::new(n);
let mut row = std::collections::HashMap::new();
let mut col = std::collections::HashMap::new();
// 依次遍历各个石头
for i in 0..n {
let (r, c) = (stones[i][0], stones[i][1]);
// 如果当前石子的行坐标有相同的, 则将下标其合并进并查集中
if let Some(j) = row.get(&r) {
ufs.union(*j, i);
} else {
// 否则没有相同的行, 则将(行号r, 节点下标i)记录到hashmap中
row.insert(r, i);
}
if let Some(j) = col.get(&c) {
ufs.union(*j, i);
} else {
col.insert(c, i);
}
}
(n - ufs.size()) as i32
}
}
// @lc code=end
|