除 0
号房间外的其余所有房间都被锁住
因此 entrypoint
只有一个.
pub fn can_visit_all_rooms(rooms: Vec<Vec<i32>>) -> bool {
use std::collections::HashSet;
use std::collections::VecDeque;
let mut queue = VecDeque::new();
let mut visited = HashSet::new();
queue.push_back(0);
visited.insert(0);
while let Some(n) = queue.pop_front() {
let room = rooms.get(n).unwrap();
for &r in room.iter(){
if !visited.insert(r) {
continue;
}
queue.push_back(r as usize)
}
}
visited.len() == rooms.len()
}
由于 HashSet
这里也只是用了 insert
和 contain
两个方法, 因此换成 并查集判定也是OK的.
甚至内存表现上, 并查集更优.
pub fn can_visit_all_rooms(rooms: Vec<Vec<i32>>) -> bool {
use std::collections::VecDeque;
let mut uf = UnionFind::new(rooms.len());
let mut queue = VecDeque::new();
queue.push_back(0);
while let Some(curr) = queue.pop_front() {
let room = rooms.get(curr).unwrap();
for &r in room.iter() {
if uf.is_connected(curr, r as usize) {
continue;
}
uf.connect(curr, r as usize);
queue.push_back(r as usize);
}
}
uf.count() == 1
}
struct UnionFind {
count: usize, // 连通分量的个数, 总共分成了几组
parent: std::cell::RefCell<Vec<usize>>, // 记录每个节点的父节点,父节点为自身的是根节点
size: Vec<usize>, // 记录每个连通分量的大小
}
impl UnionFind {
pub fn new(size: usize) -> Self {
Self {
count: size,
parent: std::cell::RefCell::new((0..size).collect()),
size: vec![1; size],
}
}
pub fn count(&self) -> usize {
self.count
}
pub fn find(&self, p: usize) -> usize {
let mut root = p;
while root != self.parent.borrow()[root] {
root = self.parent.borrow()[root];
}
let mut p = p;
while p != root {
let next = self.parent.borrow()[p];
self.parent.borrow_mut()[p] = root;
p = next;
}
root
}
pub fn is_connected(&self, p: usize, q: usize) -> bool {
self.find(p) == self.find(q)
}
pub fn connect(&mut self, p: usize, q: usize) {
let (p_root, q_root) = (self.find(p), self.find(q));
if p_root == q_root {
return;
}
if self.size[p_root] < self.size[q_root] {
self.parent.borrow_mut()[p_root] = q_root;
self.size[q_root] += self.size[p_root];
} else {
self.parent.borrow_mut()[q_root] = p_root;
self.size[p_root] += self.size[q_root];
}
self.count -= 1;
}
}