From e51aa14c80bef39005e8ae02c3d2729f4ef18d7c Mon Sep 17 00:00:00 2001 From: Denis Dalecki Date: Tue, 31 Oct 2023 01:24:00 +0100 Subject: [PATCH] weighted graph --- ...disjoint_set.rs => disjoint_sets_union.rs} | 150 +++++---- rust/src/common/mod.rs | 3 +- rust/src/common/trie.rs | 7 +- rust/src/common/weighted_graph.rs | 308 ++++++++++++++++++ .../link.txt | 1 - .../delete_duplicate_folders_in_system/mod.rs | 97 ------ rust/src/implement_magic_dictionary/mod.rs | 2 - .../mod.rs | 4 +- rust/src/lib.rs | 2 + 9 files changed, 405 insertions(+), 169 deletions(-) rename rust/src/common/{disjoint_set.rs => disjoint_sets_union.rs} (62%) create mode 100644 rust/src/common/weighted_graph.rs delete mode 100644 rust/src/delete_duplicate_folders_in_system/link.txt delete mode 100644 rust/src/delete_duplicate_folders_in_system/mod.rs diff --git a/rust/src/common/disjoint_set.rs b/rust/src/common/disjoint_sets_union.rs similarity index 62% rename from rust/src/common/disjoint_set.rs rename to rust/src/common/disjoint_sets_union.rs index 52fc286..497acaa 100644 --- a/rust/src/common/disjoint_set.rs +++ b/rust/src/common/disjoint_sets_union.rs @@ -2,34 +2,42 @@ use std::collections::{HashMap, HashSet}; pub trait UnionFind { fn join(&mut self, item1: usize, item2: usize) -> usize; - fn connected(&mut self, item1: &usize, item2: &usize) -> bool; + fn connected(&mut self, item1: usize, item2: usize) -> bool; } #[derive(Debug, Default)] -pub struct DisjointHashSet { +pub struct HashMapDSU { mapping: HashMap, } -impl DisjointHashSet { +impl HashMapDSU { + /// create a new empty set pub fn new() -> Self { - DisjointHashSet::default() + HashMapDSU::default() } + /// get the number of items in the set + pub fn len(&self) -> usize { + self.mapping.len() + } + + /// check if the set is empty pub fn is_empty(&self) -> bool { self.mapping.is_empty() } - pub fn contains(&self, item: &usize) -> bool { - self.mapping.contains_key(item) + /// check if the set contains the item + pub fn contains(&self, item: usize) -> bool { + self.mapping.contains_key(&item) } /// get the id of the item's component if it's inserted /// otherwise return None - pub fn id_of(&self, item: &usize) -> Option { + pub fn component_id_of(&self, item: usize) -> Option { let mut curr_item = item; - while let Some(next_item) = self.mapping.get(curr_item) { + while let Some(&next_item) = self.mapping.get(&curr_item) { if next_item == curr_item { - return Some(*curr_item); + return Some(curr_item); } else { curr_item = next_item; } @@ -38,17 +46,17 @@ impl DisjointHashSet { } /// get the id of the item's component and optimize the whole ids chain while doing it - fn get_id_and_optimize(&mut self, item: &usize) -> Option { - let chain_of_ids = |item: &usize| { + fn get_id_and_optimize(&mut self, item: usize) -> Option { + let chain_of_ids = |item: usize| { let mut chain = vec![]; let mut curr_item = item; - while let Some(next_item) = self.mapping.get(curr_item) { + while let Some(&next_item) = self.mapping.get(&curr_item) { if next_item == curr_item { - chain.push(*curr_item); + chain.push(curr_item); return chain; } else { - chain.push(*curr_item); + chain.push(curr_item); curr_item = next_item; } } @@ -67,9 +75,9 @@ impl DisjointHashSet { } /// insert the item if it isn't present - /// otherwise return it's component id + /// return it's component id pub fn insert(&mut self, item: usize) -> usize { - if let Some(id) = self.id_of(&item) { + if let Some(id) = self.component_id_of(item) { id } else { self.mapping.insert(item, item); @@ -77,18 +85,20 @@ impl DisjointHashSet { } } + /// get all connected components of the set pub fn components(&self) -> HashMap> { - self.mapping.keys().fold(HashMap::new(), |mut map, item| { - let id = self.id_of(item).unwrap(); - map.entry(id).or_insert(vec![]).push(*item); + self.mapping.keys().fold(HashMap::new(), |mut map, &item| { + let id = self.component_id_of(item).unwrap(); + map.entry(id).or_insert(vec![]).push(item); map }) } + /// get the number of connected components in the set pub fn components_count(&self) -> usize { self.mapping .keys() - .map(|k| self.id_of(k).unwrap()) + .map(|&k| self.component_id_of(k).unwrap()) .fold(HashSet::new(), |mut set, item| { set.insert(item); set @@ -97,13 +107,13 @@ impl DisjointHashSet { } } -impl UnionFind for DisjointHashSet { +impl UnionFind for HashMapDSU { /// join two items and return id of the connected component they are in after joining /// if some (or both) of the items wasn't present, it's inserted before joining fn join(&mut self, item1: usize, item2: usize) -> usize { match ( - self.get_id_and_optimize(&item1), - self.get_id_and_optimize(&item2), + self.get_id_and_optimize(item1), + self.get_id_and_optimize(item2), ) { (None, None) => { self.mapping.insert(item1, item1); @@ -128,8 +138,11 @@ impl UnionFind for DisjointHashSet { } } - fn connected(&mut self, item1: &usize, item2: &usize) -> bool { - self.get_id_and_optimize(item1) == self.get_id_and_optimize(item2) + fn connected(&mut self, item1: usize, item2: usize) -> bool { + let id1 = self.get_id_and_optimize(item1); + let id2 = self.get_id_and_optimize(item2); + + id1 == id2 && id1.is_some() } } @@ -147,12 +160,12 @@ mod tests { use rstest::{fixture, rstest}; #[fixture] - fn empty_set() -> DisjointHashSet { - DisjointHashSet::new() + fn empty_set() -> HashMapDSU { + HashMapDSU::new() } #[fixture] - fn set_100_orphans(mut empty_set: DisjointHashSet) -> DisjointHashSet { + fn set_100_orphans(mut empty_set: HashMapDSU) -> HashMapDSU { for i in 0..100 { empty_set.insert(i); } @@ -161,7 +174,7 @@ mod tests { } #[fixture] - fn set_1to5_linear(mut empty_set: DisjointHashSet) -> DisjointHashSet { + fn set_1to5_linear(mut empty_set: HashMapDSU) -> HashMapDSU { for i in 1..5 { empty_set.join(i, i + 1); } @@ -202,7 +215,7 @@ mod tests { } #[fixture] - fn set_10by10(set_100_orphans: DisjointHashSet) -> DisjointHashSet { + fn set_10by10(set_100_orphans: HashMapDSU) -> HashMapDSU { let mut set = set_100_orphans; for component_idx in 0..10 { @@ -223,46 +236,61 @@ mod tests { ///////////////////////////////////// #[rstest] - fn inserting_new_item_increments_id(empty_set: DisjointHashSet) { + fn inserting_new_item_increments_id(empty_set: HashMapDSU) { let mut set = empty_set; for i in 0..1000 { - assert_returns!(i as usize, DisjointHashSet::insert, &mut set, i); + assert_returns!(i as usize, HashMapDSU::insert, &mut set, i); } } #[rstest] - fn inserted_items_are_have_unique_ids(set_100_orphans: DisjointHashSet) { + fn inserted_items_are_have_unique_ids(set_100_orphans: HashMapDSU) { for i in 0..100 { for j in (i + 1)..100 { - assert_ne!(set_100_orphans.id_of(&i), set_100_orphans.id_of(&j)); + assert_ne!(set_100_orphans.component_id_of(i), set_100_orphans.component_id_of(j)); + } + } + } + + #[rstest] + fn items_in_empty_set_are_disconnected(mut empty_set: HashMapDSU) { + for i in 0..10 { + for j in (i + 1)..10 { + assert_returns!( + false, + HashMapDSU::connected, + &mut empty_set, + i, + j + ); } } } #[rstest] - fn inserted_items_are_disconnected(mut set_100_orphans: DisjointHashSet) { + fn inserted_items_are_disconnected(mut set_100_orphans: HashMapDSU) { for i in 0..100 { for j in (i + 1)..100 { assert_returns!( false, - DisjointHashSet::connected, + HashMapDSU::connected, &mut set_100_orphans, - &i, - &j + i, + j ); } } - assert_returns!(100, DisjointHashSet::components_count, &set_100_orphans); + assert_returns!(100, HashMapDSU::components_count, &set_100_orphans); } #[rstest] - fn components_count_is_correct(set_10by10: DisjointHashSet) { - assert_returns!(10, DisjointHashSet::components_count, &set_10by10); + fn components_count_is_correct(set_10by10: HashMapDSU) { + assert_returns!(10, HashMapDSU::components_count, &set_10by10); } #[rstest] - fn components_content_is_correct(set_10by10: DisjointHashSet) { + fn components_content_is_correct(set_10by10: HashMapDSU) { let mut components: Vec> = set_10by10.components().values().cloned().collect(); components.sort_by_key(|values| values[0]); @@ -270,11 +298,11 @@ mod tests { let expected_content: Vec = ((i * 10)..((i + 1) * 10)).collect(); assert_that(&components[i as usize]).contains_all_of(&expected_content.iter()); } - assert_returns!(10, DisjointHashSet::components_count, &set_10by10); + assert_returns!(10, HashMapDSU::components_count, &set_10by10); } #[rstest] - fn joining_n_components_makes_single_component(mut set_10by10: DisjointHashSet) { + fn joining_n_components_makes_single_component(mut set_10by10: HashMapDSU) { let mut rng = thread_rng(); let some_node_for_each_component: Vec = (0..10) @@ -288,11 +316,11 @@ mod tests { set_10by10.join(from, to); } - assert_returns!(1, DisjointHashSet::components_count, &set_10by10); + assert_returns!(1, HashMapDSU::components_count, &set_10by10); } #[rstest] - fn joining_items_makes_their_ids_equal(mut set_100_orphans: DisjointHashSet) { + fn joining_items_makes_their_ids_equal(mut set_100_orphans: HashMapDSU) { let mut rng = thread_rng(); let id_distr1 = rand::distributions::Uniform::from(0..100); let id_distr2 = rand::distributions::Uniform::from(0..100); @@ -302,38 +330,38 @@ mod tests { let item2 = id_distr2.sample(&mut rng); set_100_orphans.join(item1, item2); - assert_eq!(set_100_orphans.id_of(&item1), set_100_orphans.id_of(&item2)); + assert_eq!(set_100_orphans.component_id_of(item1), set_100_orphans.component_id_of(item2)); } } #[rstest] - fn item_has_id_of_its_terminal_link(set_1to5_linear: DisjointHashSet) { + fn item_has_id_of_its_terminal_link(set_1to5_linear: HashMapDSU) { for i in 1..=5 { - assert_returns!(Some(1), DisjointHashSet::id_of, &set_1to5_linear, &i); + assert_returns!(Some(1), HashMapDSU::component_id_of, &set_1to5_linear, i); } } #[rstest] fn components_are_valid_manual() { - let mut set = DisjointHashSet::new(); + let mut set = HashMapDSU::new(); set.join(1, 2); - assert_returns!(1, DisjointHashSet::components_count, &set); + assert_returns!(1, HashMapDSU::components_count, &set); set.join(3, 4); - assert_returns!(2, DisjointHashSet::components_count, &set); + assert_returns!(2, HashMapDSU::components_count, &set); set.join(5, 6); - assert_returns!(3, DisjointHashSet::components_count, &set); + assert_returns!(3, HashMapDSU::components_count, &set); set.join(7, 8); - assert_returns!(4, DisjointHashSet::components_count, &set); + assert_returns!(4, HashMapDSU::components_count, &set); set.join(1, 4); - assert_returns!(3, DisjointHashSet::components_count, &set); + assert_returns!(3, HashMapDSU::components_count, &set); set.join(7, 6); - assert_returns!(2, DisjointHashSet::components_count, &set); + assert_returns!(2, HashMapDSU::components_count, &set); set.join(6, 4); - assert_returns!(1, DisjointHashSet::components_count, &set); + assert_returns!(1, HashMapDSU::components_count, &set); let component = set.components().values().next().cloned().unwrap(); @@ -344,16 +372,16 @@ mod tests { proptest! { #[test] fn new_set_contains_nothing(num in 0..1000) { - let set = DisjointHashSet::new(); + let set = HashMapDSU::new(); - prop_assert!(!set.contains(&(num as usize))); + prop_assert!(!set.contains(num as usize)); } #[test] fn id_of_returns_none_if_item_isnt_inserted(num in 0..1000) { - let set = DisjointHashSet::new(); + let set = HashMapDSU::new(); - prop_assert!(set.id_of(&(num as usize)).is_none()); + prop_assert!(set.component_id_of(num as usize).is_none()); } } } diff --git a/rust/src/common/mod.rs b/rust/src/common/mod.rs index c3915ce..9b75710 100644 --- a/rust/src/common/mod.rs +++ b/rust/src/common/mod.rs @@ -1,7 +1,8 @@ pub mod binary_tree; -pub mod disjoint_set; +pub mod disjoint_sets_union; pub mod linked_list; pub mod trie; +pub mod weighted_graph; #[macro_export] macro_rules! format_expr_kv { diff --git a/rust/src/common/trie.rs b/rust/src/common/trie.rs index 4844a98..b9b640a 100644 --- a/rust/src/common/trie.rs +++ b/rust/src/common/trie.rs @@ -251,7 +251,6 @@ impl From> for CharTrie { mod test { use crate::assert_returns; use rstest::{fixture, rstest}; - use std::path::PathBuf; use lazy_static::lazy_static; use proptest::proptest; @@ -280,11 +279,9 @@ mod test { random_words }; static ref WORDS_100: Vec = { - let words_file_path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/words100.txt"); + let words_file_content = include_str!("testdata/words100.txt"); - std::fs::read_to_string(words_file_path) - .unwrap() + words_file_content .trim() .split("\n") .map(|s| s.to_owned()) diff --git a/rust/src/common/weighted_graph.rs b/rust/src/common/weighted_graph.rs new file mode 100644 index 0000000..efca8ac --- /dev/null +++ b/rust/src/common/weighted_graph.rs @@ -0,0 +1,308 @@ +use std::collections::HashMap; + +use crate::common::disjoint_sets_union::{HashMapDSU, UnionFind}; + +type VertexID = usize; + +#[derive(Debug, PartialEq, Eq)] +pub struct Vertex { + pub id: VertexID, + pub value: T, +} + +impl Vertex { + pub fn new(id: VertexID, value: T) -> Self { + Vertex { id, value } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Edge { + pub from: VertexID, + pub to: VertexID, + pub weight: Weight, +} + +impl Edge { + pub fn new(from: VertexID, to: VertexID, weight: Weight) -> Self { + Edge { from, to, weight } + } +} + +pub struct WeightedGraph { + vertices: HashMap, + adjacencies: HashMap>, +} + +impl WeightedGraph { + /// create a new empty graph + pub fn new() -> Self { + WeightedGraph { + vertices: HashMap::new(), + adjacencies: HashMap::new(), + } + } + + /// add a new vertex to the graph + pub fn add_vertex(&mut self, vertex: Vertex) { + self.vertices.insert(vertex.id, vertex.value); + } + + /// insert a new vertex into the graph + pub fn insert(&mut self, id: VertexID, value: T) { + self.add_vertex(Vertex { id, value }) + } + + /// check if the graph contains a vertex with a given id + pub fn contains(&self, id: VertexID) -> bool { + self.vertices.contains_key(&id) + } + + /// add an edge to the graph + pub fn add_edge(&mut self, edge: Edge) { + assert!(self.contains(edge.from), "can't connect non-existent vertex"); + assert!(self.contains(edge.to), "can't connect non-existent vertex"); + + let id1 = edge.from; + let id2 = edge.to; + let weight = edge.weight; + + self.adjacencies.entry(id1).or_default().insert(id2, weight); + self.adjacencies.entry(id2).or_default().insert(id1, weight); + } + + /// connect two vertices with an edge of a given weight + pub fn connect(&mut self, from: VertexID, to: VertexID, weight: Weight) { + self.add_edge(Edge { from, to, weight }) + } + + /// check if two vertices are connected + pub fn connected(&self, this: VertexID, that: VertexID) -> bool { + let Some(links) = self.adjacencies.get(&this) else { + return false; + }; + + links.contains_key(&that) + } + + /// number of vertices in the graph + pub fn len(&self) -> usize { + self.vertices.len() + } + + /// check if the graph is empty + pub fn is_empty(&self) -> bool { + self.vertices.is_empty() + } + + /// number of edges in the graph + pub fn edges_count(&self) -> usize { + self.adjacencies.values().map(|links| links.len()).sum::() / 2 + } + + /// iterator over all vertices in the graph + pub fn vertices(&self) -> impl Iterator> { + self.vertices + .iter() + .map(|(k, v)| Vertex { id: *k, value: v }) + } + + /// iterator over all edges in the graph + pub fn edges(&self) -> impl Iterator> + '_ { + self.adjacencies.iter().flat_map(|(from, links)| { + links.iter().filter_map(|(to, weight)| { + if *from < *to { + Some(Edge { + from: *from, + to: *to, + weight: *weight, + }) + } else { + None + } + }) + }) + } + + /// iterator over all vertices which are adjacent to the vertex with a given id + pub fn adjacent_vertices(&self, id: VertexID) -> impl Iterator> + '_ { + let iterator = self.adjacent_edges(id).filter_map(|edge| { + self.vertices.get(&edge.to).map(|value| Vertex { + id: edge.to, + value, + }) + }); + + iterator + } + + // iterator over all edges which are adjacent to the vertex with a given id + pub fn adjacent_edges(&self, id: VertexID) -> Box> + '_> { + let Some(links) = self.adjacencies.get(&id) else { + return Box::new(std::iter::empty()); + }; + + let iterator = links.iter().map(move |(&other_id, &weight)| { + Edge { + from: id, + to: other_id, + weight + } + }); + + Box::new(iterator) + } + + /// Compute minimum spanning tree using Kruskal's algorithm + pub fn mst(&self) -> Vec> + where + Weight: Ord, + { + let mut result = vec![]; + + let mut edges: Vec<_> = self.edges().collect(); + edges.sort_unstable_by_key(|edge| edge.weight); + + let mut dsu = HashMapDSU::new(); + + for edge in edges { + if result.len() == self.len() - 1 { + break; + } + + if dsu.connected(edge.from, edge.to) { + continue; + } + + dsu.join(edge.from, edge.to); + result.push(edge); + } + + result + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_len() { + let mut graph: WeightedGraph<_, i32> = WeightedGraph::new(); + assert_eq!(graph.len(), 0); + + graph.insert(0, "A"); + assert_eq!(graph.len(), 1); + + graph.insert(1, "B"); + assert_eq!(graph.len(), 2); + } + + #[test] + fn test_contains() { + let mut graph: WeightedGraph<_, i32> = WeightedGraph::new(); + graph.insert(5, "A"); + graph.insert(2, "B"); + + assert!(graph.contains(5)); + assert!(graph.contains(2)); + assert!(!graph.contains(0)); + assert!(!graph.contains(1)); + assert!(!graph.contains(8)); + } + + + #[test] + fn test_connected() { + let mut graph = WeightedGraph::new(); + graph.insert(0, "A"); + graph.insert(1, "B"); + graph.add_edge(Edge::new(0, 1, 1.0)); + + assert!(graph.connected(0, 1)); + assert!(graph.connected(1, 0)); + assert!(!graph.connected(0, 2)); + } + + #[test] + fn test_vertices() { + let mut graph: WeightedGraph<_, i32> = WeightedGraph::new(); + graph.insert(0, "A"); + graph.insert(1, "B"); + graph.insert(2, "C"); + + let vertices: Vec<_> = graph.vertices().collect(); + assert_eq!(vertices.len(), 3); + assert!(vertices.contains(&Vertex::new(0, &"A"))); + assert!(vertices.contains(&Vertex::new(1, &"B"))); + assert!(vertices.contains(&Vertex::new(2, &"C"))); + } + + #[test] + fn test_edges() { + let mut graph = WeightedGraph::new(); + graph.insert(0, "A"); + graph.insert(1, "B"); + graph.insert(2, "C"); + graph.add_edge(Edge::new(0, 1, 1.0)); + graph.add_edge(Edge::new(1, 2, 2.0)); + + assert_eq!(graph.edges_count(), 2); + + let edges: Vec<_> = graph.edges().collect(); + assert_eq!(edges.len(), 2); + assert!(edges.contains(&Edge::new(0, 1, 1.0))); + assert!(edges.contains(&Edge::new(1, 2, 2.0))); + } + + #[test] + fn test_adjacent_vertices() { + let mut graph = WeightedGraph::new(); + graph.insert(0, "A"); + graph.insert(1, "B"); + graph.insert(2, "C"); + graph.add_edge(Edge::new(0, 1, 1.0)); + graph.add_edge(Edge::new(1, 2, 2.0)); + + let vertices: Vec<_> = graph.adjacent_vertices(1).collect(); + assert_eq!(vertices.len(), 2); + assert!(vertices.contains(&Vertex::new(0, &"A"))); + assert!(vertices.contains(&Vertex::new(2, &"C"))); + } + + #[test] + fn test_adjacent_edges() { + let mut graph = WeightedGraph::new(); + graph.insert(0, "A"); + graph.insert(1, "B"); + graph.insert(2, "C"); + graph.add_edge(Edge::new(0, 1, 1.0)); + graph.add_edge(Edge::new(1, 2, 2.0)); + + let edges: Vec<_> = graph.adjacent_edges(1).collect(); + assert_eq!(edges.len(), 2); + assert!(edges.contains(&Edge::new(1, 0, 1.0))); + assert!(edges.contains(&Edge::new(1, 2, 2.0))); + } + + #[test] + fn test_mst() { + let mut graph = WeightedGraph::new(); + graph.insert(0, "A"); + graph.insert(1, "B"); + graph.insert(2, "C"); + graph.insert(3, "D"); + graph.add_edge(Edge::new(0, 1, 1)); + graph.add_edge(Edge::new(0, 2, 2)); + graph.add_edge(Edge::new(0, 3, 3)); + graph.add_edge(Edge::new(1, 2, 4)); + graph.add_edge(Edge::new(1, 3, 5)); + graph.add_edge(Edge::new(2, 3, 6)); + + let mst = graph.mst(); + assert_eq!(mst.len(), 3); + assert!(mst.contains(&Edge::new(0, 1, 1))); + assert!(mst.contains(&Edge::new(0, 2, 2))); + assert!(mst.contains(&Edge::new(0, 3, 3))); + } +} diff --git a/rust/src/delete_duplicate_folders_in_system/link.txt b/rust/src/delete_duplicate_folders_in_system/link.txt deleted file mode 100644 index 03ea6a3..0000000 --- a/rust/src/delete_duplicate_folders_in_system/link.txt +++ /dev/null @@ -1 +0,0 @@ -https://leetcode.com/problems/delete-duplicate-folders-in-system diff --git a/rust/src/delete_duplicate_folders_in_system/mod.rs b/rust/src/delete_duplicate_folders_in_system/mod.rs deleted file mode 100644 index 219a8f0..0000000 --- a/rust/src/delete_duplicate_folders_in_system/mod.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::common::trie::TrieNode; -type Trie = crate::common::trie::Trie; - -pub struct Solution {} - -///////////////////////////////////////////////////// -impl Solution { - pub fn unique_forward_paths(paths: Vec>) -> Vec> { - let mut trie = Trie::new(); - for path in paths { - trie.insert(path.into_iter()); - } - - let mut result = vec![]; - - let mut stack = vec![]; - stack.push(trie.root()); - - while let Some(node) = stack.pop() { - if node.children_count() == 0 { - - } - } - - result - } - - fn rec_fn<'a>(node: &'a TrieNode, current_path: &mut Vec<&'a TrieNode>) { - current_path.push(node); - - match node.children_count() { - 0 => {} - 1 => { - Solution::rec_fn(node.children().next().unwrap().1, current_path); - } - _ => { - println!("current path has multiple children"); - println!( - "{:?}", - current_path - .iter() - .map(|node| &node.character) - .collect::>() - ); - // mark - for (_, child_node) in node.children() { - Solution::rec_fn(child_node, current_path); - } - } - } - - current_path.pop(); - } - - pub fn delete_duplicate_folder(paths: Vec>) -> Vec> { - let mut paths_trie = Trie::new(); - for path in paths { - paths_trie.insert(path.into_iter().rev()); - } - - let mut current_path = vec![]; - Solution::rec_fn(paths_trie.root(), &mut current_path); - - println!("{:?}", paths_trie); - - vec![] - } -} -////////////////////////////////////////////////////// - -#[cfg(test)] -mod tests { - use super::*; - use crate::{assert_eq, vec2d}; - use rstest::rstest; - - #[rstest] - #[case( - vec2d![["a"],["c"],["a","b"],["c","b"],["a","b","x"],["a","b","x","y"],["w"],["w","y"]], - vec2d![["c"],["c","b"],["a"],["a","b"]] - )] - fn it_works(#[case] _input: Vec>, #[case] _expected_result: Vec>) { - let input: Vec> = _input - .into_iter() - .map(|strs| strs.into_iter().map(|s| s.to_owned()).collect()) - .collect(); - - let expected_result: Vec> = _expected_result - .into_iter() - .map(|strs| strs.into_iter().map(|s| s.to_owned()).collect()) - .collect(); - - let actual_result = Solution::delete_duplicate_folder(input); - - assert_eq!(actual_result, expected_result); - } -} diff --git a/rust/src/implement_magic_dictionary/mod.rs b/rust/src/implement_magic_dictionary/mod.rs index 19047f1..c5acfad 100644 --- a/rust/src/implement_magic_dictionary/mod.rs +++ b/rust/src/implement_magic_dictionary/mod.rs @@ -71,8 +71,6 @@ impl MagicDictionary { #[cfg(test)] mod tests { - use std::iter::zip; - use super::*; use crate::assert_returns; use rstest::{fixture, rstest}; diff --git a/rust/src/largest_component_size_by_common_factor/mod.rs b/rust/src/largest_component_size_by_common_factor/mod.rs index d23e867..4bebbce 100644 --- a/rust/src/largest_component_size_by_common_factor/mod.rs +++ b/rust/src/largest_component_size_by_common_factor/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::common::disjoint_set::{DisjointHashSet, UnionFind}; +use crate::common::disjoint_sets_union::{HashMapDSU, UnionFind}; pub struct Solution {} @@ -26,7 +26,7 @@ impl Solution { pub fn largest_component_size(nums: Vec) -> i32 { let nums_set: HashSet = nums.iter().map(|&n| n as usize).collect(); - let mut set = DisjointHashSet::new(); + let mut set = HashMapDSU::new(); for num in nums.into_iter().map(|i| i as usize) { set.insert(num); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index dbaca7c..969a45f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + pub mod common; mod count_number_of_homogenous_substrings; mod count_primes;