mirror of
https://gitlab.com/mfocko/LeetCode.git
synced 2024-11-09 15:59:06 +01:00
246 lines
6.2 KiB
Rust
246 lines
6.2 KiB
Rust
use std::{collections::VecDeque, ops::BitOr};
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
#[repr(u8)]
|
|
enum Reachable {
|
|
None = 0x0,
|
|
Pacific = 0x1,
|
|
Atlantic = 0x2,
|
|
Both = 0x3,
|
|
}
|
|
|
|
impl Reachable {
|
|
fn new(y: usize, x: usize, max_y: usize, max_x: usize) -> Reachable {
|
|
let reaches_pacific = y == 0 || x == 0;
|
|
let reaches_atlantic = y == max_y - 1 || x == max_x - 1;
|
|
|
|
match (reaches_pacific, reaches_atlantic) {
|
|
(true, true) => Reachable::Both,
|
|
(true, _) => Reachable::Pacific,
|
|
(_, true) => Reachable::Atlantic,
|
|
(_, _) => Reachable::None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<u8> for Reachable {
|
|
fn from(u: u8) -> Self {
|
|
match u {
|
|
0 => Reachable::None,
|
|
1 => Reachable::Pacific,
|
|
2 => Reachable::Atlantic,
|
|
3 => Reachable::Both,
|
|
_ => panic!("Invalid conversion"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Reachable> for u8 {
|
|
fn from(r: Reachable) -> Self {
|
|
match r {
|
|
Reachable::None => 0,
|
|
Reachable::Pacific => 1,
|
|
Reachable::Atlantic => 2,
|
|
Reachable::Both => 3,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BitOr for Reachable {
|
|
type Output = Reachable;
|
|
|
|
fn bitor(self, rhs: Self) -> Self::Output {
|
|
let (lhs, rhs): (u8, u8) = (self.into(), rhs.into());
|
|
(lhs | rhs).into()
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq)]
|
|
enum State {
|
|
Unvisited,
|
|
Queued,
|
|
Visited,
|
|
}
|
|
|
|
struct Vertex {
|
|
height: i32,
|
|
reaches: Reachable,
|
|
state: State,
|
|
}
|
|
|
|
struct Graph {
|
|
vertices: Vec<Vec<Vertex>>,
|
|
max_y: usize,
|
|
max_x: usize,
|
|
}
|
|
|
|
impl Graph {
|
|
pub fn new(heights: &Vec<Vec<i32>>) -> Graph {
|
|
let max_y = heights.len();
|
|
let max_x = heights[0].len();
|
|
|
|
Graph {
|
|
vertices: heights
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(y, row)| {
|
|
row.iter()
|
|
.enumerate()
|
|
.map(|(x, h)| Vertex {
|
|
height: *h,
|
|
reaches: Reachable::new(y, x, max_y, max_x),
|
|
state: State::Unvisited,
|
|
})
|
|
.collect()
|
|
})
|
|
.collect(),
|
|
max_y,
|
|
max_x,
|
|
}
|
|
}
|
|
|
|
pub fn vertices(&self) -> &Vec<Vec<Vertex>> {
|
|
&self.vertices
|
|
}
|
|
|
|
fn _vertex(&mut self, y: i32, x: i32) -> Option<&mut Vertex> {
|
|
if y >= 0 && y < self.max_y as i32 && x >= 0 && x < self.max_x as i32 {
|
|
Some(&mut self.vertices[y as usize][x as usize])
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn _run_bfs(&mut self, q: &mut VecDeque<(i32, i32)>) {
|
|
q.iter().for_each(|&(y, x)| {
|
|
self._vertex(y, x).unwrap().state = State::Queued;
|
|
});
|
|
|
|
while let Some((y, x)) = q.pop_front() {
|
|
self._vertex(y, x).unwrap().state = State::Visited;
|
|
let h = self._vertex(y, x).unwrap().height;
|
|
let r = self._vertex(y, x).unwrap().reaches;
|
|
|
|
for d in [-1, 1] {
|
|
for (next_y, next_x) in [(y + d, x), (y, x + d)] {
|
|
if let Some(v) = self._vertex(next_y, next_x) {
|
|
if matches!(v.state, State::Unvisited) && h <= v.height {
|
|
q.push_back((next_y, next_x));
|
|
v.state = State::Queued;
|
|
v.reaches = r | v.reaches;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn _reset(&mut self) {
|
|
for y in 0..self.max_y {
|
|
for x in 0..self.max_x {
|
|
self.vertices[y][x].state = State::Unvisited;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn bfs(&mut self) {
|
|
// Run BFS from Pacific Ocean
|
|
self._run_bfs(&mut VecDeque::from(
|
|
(0..self.max_x)
|
|
.map(|x| (0_i32, x as i32))
|
|
.chain((0..self.max_y).map(|y| (y as i32, 0_i32)))
|
|
.collect::<Vec<(i32, i32)>>(),
|
|
));
|
|
|
|
// Reset the visited
|
|
self._reset();
|
|
|
|
// Run BFS from Atlantic Ocean
|
|
self._run_bfs(&mut VecDeque::from(
|
|
(0..self.max_x)
|
|
.map(|x| (self.max_y as i32 - 1, x as i32))
|
|
.chain((0..self.max_y).map(|y| (y as i32, self.max_x as i32 - 1)))
|
|
.collect::<Vec<(i32, i32)>>(),
|
|
));
|
|
}
|
|
}
|
|
|
|
impl Solution {
|
|
pub fn pacific_atlantic(heights: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
|
let mut g = Graph::new(&heights);
|
|
g.bfs();
|
|
|
|
g.vertices().iter().for_each(|row| {
|
|
row.iter().for_each(|v| {
|
|
print!("{:?} ", v.reaches);
|
|
});
|
|
|
|
println!();
|
|
});
|
|
|
|
g.vertices()
|
|
.iter()
|
|
.enumerate()
|
|
.flat_map(|(y, row)| {
|
|
row.iter()
|
|
.enumerate()
|
|
.filter(|&(_, v)| matches!(v.reaches, Reachable::Both))
|
|
.map(move |(x, _)| vec![y as i32, x as i32])
|
|
})
|
|
.collect()
|
|
}
|
|
}
|
|
struct Solution {}
|
|
|
|
fn main() {
|
|
println!("Hello World!");
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_example_1() {
|
|
assert_eq!(
|
|
Solution::pacific_atlantic(vec![
|
|
vec![1, 2, 2, 3, 5],
|
|
vec![3, 2, 3, 4, 4],
|
|
vec![2, 4, 5, 3, 1],
|
|
vec![6, 7, 1, 4, 5],
|
|
vec![5, 1, 1, 2, 4]
|
|
]),
|
|
vec![
|
|
vec![0, 4],
|
|
vec![1, 3],
|
|
vec![1, 4],
|
|
vec![2, 2],
|
|
vec![3, 0],
|
|
vec![3, 1],
|
|
vec![4, 0]
|
|
]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_example_2() {
|
|
assert_eq!(Solution::pacific_atlantic(vec![vec![1]]), vec![vec![0, 0]]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_wrong() {
|
|
assert_eq!(
|
|
Solution::pacific_atlantic(vec![vec![3, 3, 3], vec![3, 1, 3], vec![0, 2, 4]]),
|
|
vec![
|
|
vec![0, 0],
|
|
vec![0, 1],
|
|
vec![0, 2],
|
|
vec![1, 0],
|
|
vec![1, 2],
|
|
vec![2, 0],
|
|
vec![2, 1],
|
|
vec![2, 2]
|
|
]
|
|
);
|
|
}
|
|
}
|