From b998cfdf47c7144e2f91148ba84c5eefca980f2d Mon Sep 17 00:00:00 2001 From: godf <39857185+a1396537376@users.noreply.github.com> Date: Sun, 30 Oct 2022 15:26:44 +0800 Subject: [PATCH 1/4] Add Duval algorithm (#414) --- README.md | 1 + src/string/duval_algorithm.rs | 64 +++++++++++++++++++++++++++++++++++ src/string/mod.rs | 2 ++ 3 files changed, 67 insertions(+) create mode 100644 src/string/duval_algorithm.rs diff --git a/README.md b/README.md index 646d75bf737..15e96f4a446 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ These are for demonstration purposes only. - [x] [Aho-Corasick Algorithm](./src/string/aho_corasick.rs) - [x] [Boyer-Moore String Search Algorithm](./src/string/boyer_moore_search.rs) - [x] [Burrows-Wheeler transform](./src/string/burrows_wheeler_transform.rs) +- [x] [Duval Algorithm](./src/string/duval_algorithm.rs) - [x] [Knuth Morris Pratt](./src/string/knuth_morris_pratt.rs) - [x] [Levenshtein Distance](./src/string/levenshtein_distance.rs) - [x] [Manacher](./src/string/manacher.rs) diff --git a/src/string/duval_algorithm.rs b/src/string/duval_algorithm.rs new file mode 100644 index 00000000000..4d4e3c2eb57 --- /dev/null +++ b/src/string/duval_algorithm.rs @@ -0,0 +1,64 @@ +// A string is called simple (or a Lyndon word), if it is strictly smaller than any of its own nontrivial suffixes. +// Duval (1983) developed an algorithm for finding the standard factorization that runs in linear time and constant space. Source: https://en.wikipedia.org/wiki/Lyndon_word +fn factorization_with_duval(s: &[u8]) -> Vec { + let n = s.len(); + let mut i = 0; + let mut factorization: Vec = Vec::new(); + + while i < n { + let mut j = i + 1; + let mut k = i; + + while j < n && s[k] <= s[j] { + if s[k] < s[j] { + k = i; + } else { + k += 1; + } + j += 1; + } + + while i <= k { + factorization.push(String::from_utf8(s[i..i + j - k].to_vec()).unwrap()); + i += j - k; + } + } + + factorization +} + +pub fn duval_algorithm(s: &str) -> Vec { + return factorization_with_duval(s.as_bytes()); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_duval_multiple() { + let text = "abcdabcdababc"; + assert_eq!(duval_algorithm(text), ["abcd", "abcd", "ababc"]); + } + + #[test] + fn test_duval_all() { + let text = "aaa"; + assert_eq!(duval_algorithm(text), ["a", "a", "a"]); + } + + #[test] + fn test_duval_single() { + let text = "ababb"; + assert_eq!(duval_algorithm(text), ["ababb"]); + } + + #[test] + fn test_factorization_with_duval_multiple() { + let text = "abcdabcdababc"; + assert_eq!( + factorization_with_duval(text.as_bytes()), + ["abcd", "abcd", "ababc"] + ); + } +} diff --git a/src/string/mod.rs b/src/string/mod.rs index ccca1faf087..0e292330523 100644 --- a/src/string/mod.rs +++ b/src/string/mod.rs @@ -2,6 +2,7 @@ mod aho_corasick; mod anagram; mod boyer_moore_search; mod burrows_wheeler_transform; +mod duval_algorithm; mod hamming_distance; mod jaro_winkler_distance; mod knuth_morris_pratt; @@ -21,6 +22,7 @@ pub use self::boyer_moore_search::boyer_moore_search; pub use self::burrows_wheeler_transform::{ burrows_wheeler_transform, inv_burrows_wheeler_transform, }; +pub use self::duval_algorithm::duval_algorithm; pub use self::hamming_distance::hamming_distance; pub use self::jaro_winkler_distance::jaro_winkler_distance; pub use self::knuth_morris_pratt::knuth_morris_pratt; From bfcdde5bb11432dfa142176dc49a6dc80ec794ea Mon Sep 17 00:00:00 2001 From: Defective Detective <71999854+SpiderMath@users.noreply.github.com> Date: Sun, 30 Oct 2022 13:00:06 +0530 Subject: [PATCH 2/4] feat: Add Aliquot Sum implementation (#412) --- src/math/aliquot_sum.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/math/mod.rs | 2 ++ 2 files changed, 42 insertions(+) create mode 100644 src/math/aliquot_sum.rs diff --git a/src/math/aliquot_sum.rs b/src/math/aliquot_sum.rs new file mode 100644 index 00000000000..c09bec8a6f7 --- /dev/null +++ b/src/math/aliquot_sum.rs @@ -0,0 +1,40 @@ +/// Aliquot sum of a number is defined as the sum of the proper divisors of +/// a number, i.e. all the divisors of a number apart from the number itself +/// For example: The aliquot sum of 6 is (1 + 2 + 3) = 6, and that of 15 is +/// (1 + 3 + 5) = 9 +/// Wikipedia article on Aliquot Sum: https://en.wikipedia.org/wiki/Aliquot_sum + +pub fn aliquot_sum(number: u64) -> u64 { + if number == 1 || number == 0 { + return 0; + } + let mut sum: u64 = 0; + + for i in 1..(number / 2 + 1) { + if number % i == 0 { + sum += i; + } + } + + sum +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn one_digit_number() { + assert_eq!(aliquot_sum(6), 6); + } + + #[test] + fn two_digit_number() { + assert_eq!(aliquot_sum(15), 9); + } + + #[test] + fn three_digit_number() { + assert_eq!(aliquot_sum(343), 57); + } +} diff --git a/src/math/mod.rs b/src/math/mod.rs index f1639fdf439..ff5aa79d8cc 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -1,3 +1,4 @@ +mod aliquot_sum; mod amicable_numbers; mod armstrong_number; mod baby_step_giant_step; @@ -35,6 +36,7 @@ mod square_root; mod trial_division; mod zellers_congruence_algorithm; +pub use self::aliquot_sum::aliquot_sum; pub use self::amicable_numbers::amicable_pairs_under_n; pub use self::armstrong_number::is_armstrong_number; pub use self::baby_step_giant_step::baby_step_giant_step; From 5925833b61e08a94294bda9d7e4cc4692bd435a6 Mon Sep 17 00:00:00 2001 From: Suhail Malik Date: Sun, 30 Oct 2022 13:08:39 +0530 Subject: [PATCH 3/4] Add all combination of size k algorithm (#415) --- DIRECTORY.md | 1 + README.md | 1 + src/backtracking/all_combination_of_size_k.rs | 62 +++++++++++++++++++ src/backtracking/mod.rs | 2 + 4 files changed, 66 insertions(+) create mode 100644 src/backtracking/all_combination_of_size_k.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index f9aeebc9604..2eb768f065d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,6 +3,7 @@ ## Src * Backtracking * [Sudoku](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/sudoku.rs) + * [All Combination of Size k](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/all_combination_of_size_k.rs) * Ciphers * [Another Rot13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/another_rot13.rs) * [Caesar](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/caesar.rs) diff --git a/README.md b/README.md index 15e96f4a446..7748eda9124 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ These are for demonstration purposes only. ## [Backtracking](./src/backtracking) - [x] [Sudoku](./src/backtracking/sudoku.rs) +- [x] [All Combination of Size k](./src/backtracking/all_combination_of_size_k.rs) --- ### All implemented Algos diff --git a/src/backtracking/all_combination_of_size_k.rs b/src/backtracking/all_combination_of_size_k.rs new file mode 100644 index 00000000000..bc0560403ca --- /dev/null +++ b/src/backtracking/all_combination_of_size_k.rs @@ -0,0 +1,62 @@ +/* + In this problem, we want to determine all possible combinations of k + numbers out of 1 ... n. We use backtracking to solve this problem. + Time complexity: O(C(n,k)) which is O(n choose k) = O((n!/(k! * (n - k)!))) + + generate_all_combinations(n=4, k=2) => [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] +*/ +pub fn generate_all_combinations(n: i32, k: i32) -> Vec> { + let mut result = vec![]; + create_all_state(1, n, k, &mut vec![], &mut result); + + result +} + +fn create_all_state( + increment: i32, + total_number: i32, + level: i32, + current_list: &mut Vec, + total_list: &mut Vec>, +) { + if level == 0 { + total_list.push(current_list.clone()); + return; + } + + for i in increment..(total_number - level + 2) { + current_list.push(i); + create_all_state(i + 1, total_number, level - 1, current_list, total_list); + current_list.pop(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_output() { + let expected_res = vec![ + vec![1, 2], + vec![1, 3], + vec![1, 4], + vec![2, 3], + vec![2, 4], + vec![3, 4], + ]; + + let res = generate_all_combinations(4, 2); + + assert_eq!(expected_res, res); + } + + #[test] + fn test_empty() { + let expected_res: Vec> = vec![vec![]]; + + let res = generate_all_combinations(0, 0); + + assert_eq!(expected_res, res); + } +} diff --git a/src/backtracking/mod.rs b/src/backtracking/mod.rs index 26769777178..b580365cc22 100644 --- a/src/backtracking/mod.rs +++ b/src/backtracking/mod.rs @@ -1,3 +1,5 @@ +mod all_combination_of_size_k; mod sudoku; +pub use all_combination_of_size_k::generate_all_combinations; pub use sudoku::Sudoku; From 3649d4813fb22ba4fff4b56d4bfe765a5d45b516 Mon Sep 17 00:00:00 2001 From: Suhail Malik Date: Sun, 30 Oct 2022 13:28:55 +0530 Subject: [PATCH 4/4] Add autocomplete using trie (#416) --- DIRECTORY.md | 1 + README.md | 1 + src/string/autocomplete_using_trie.rs | 124 ++++++++++++++++++++++++++ src/string/mod.rs | 2 + 4 files changed, 128 insertions(+) create mode 100644 src/string/autocomplete_using_trie.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index 2eb768f065d..f79bf7ae59b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -125,3 +125,4 @@ * [Reverse](https://github.com/TheAlgorithms/Rust/blob/master/src/string/reverse.rs) * [Z Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/string/z_algorithm.rs) * [Hamming Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/string/hamming_distance.rs) + * [Autocomplete using Trie](https://github.com/TheAlgorithms/Rust/blob/master/src/string/autocomplete_using_trie.rs) diff --git a/README.md b/README.md index 7748eda9124..4558a38de88 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ These are for demonstration purposes only. - [x] [Jaro-Winkler Distance](./src/string/jaro_winkler_distance.rs) - [x] [Suffix Tree](./src/string/suffix_tree.rs) - [x] [Suffix Array](./src/string/suffix_array.rs) +- [x] [Autocomplete using Trie](./src/string/autocomplete_using_trie.rs) ## [General](./src/general) diff --git a/src/string/autocomplete_using_trie.rs b/src/string/autocomplete_using_trie.rs new file mode 100644 index 00000000000..37a1322fede --- /dev/null +++ b/src/string/autocomplete_using_trie.rs @@ -0,0 +1,124 @@ +/* + It autocomplete by prefix using added words. + + word List => ["apple", "orange", "oregano"] + prefix => "or" + matches => ["orange", "oregano"] +*/ + +use std::collections::HashMap; + +const END: char = '#'; + +#[derive(Debug)] +struct Trie(HashMap>); + +impl Trie { + fn new() -> Self { + Trie(HashMap::new()) + } + + fn insert(&mut self, text: String) { + let mut trie = self; + + for c in text.chars().collect::>() { + trie = trie.0.entry(c).or_insert_with(|| Box::new(Trie::new())); + } + + trie.0.insert(END, Box::new(Trie::new())); + } + + fn find(&self, prefix: String) -> Vec { + let mut trie = self; + + for c in prefix.chars().collect::>() { + let char_trie = trie.0.get(&c); + if let Some(char_trie) = char_trie { + trie = char_trie; + } else { + return vec![]; + } + } + + self._elements(trie) + .iter() + .map(|s| prefix.clone() + s) + .collect() + } + + fn _elements(&self, map: &Trie) -> Vec { + let mut results = vec![]; + + for (c, v) in map.0.iter() { + let mut sub_result = vec![]; + if c == &END { + sub_result.push("".to_owned()) + } else { + for s in self._elements(v) { + let res_string = c.to_string() + &s; + sub_result.push(res_string); + } + } + + results.extend(sub_result) + } + + results + } +} + +pub struct Autocomplete { + trie: Trie, +} + +impl Autocomplete { + fn new() -> Self { + Self { trie: Trie::new() } + } + + pub fn insert_words(&mut self, words: Vec) { + for word in words { + self.trie.insert(word); + } + } + + pub fn find_words(&self, prefix: String) -> Vec { + self.trie.find(prefix) + } +} + +impl Default for Autocomplete { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::Autocomplete; + + #[test] + fn test_autocomplete() { + let words = vec![ + "apple".to_owned(), + "orange".to_owned(), + "oregano".to_owned(), + ]; + + let mut auto_complete = Autocomplete::new(); + auto_complete.insert_words(words); + + let prefix = "app".to_owned(); + let mut auto_completed_words = auto_complete.find_words(prefix); + + assert_eq!(auto_completed_words.sort(), vec!["apple".to_owned()].sort()); + + let prefix = "or".to_owned(); + let mut auto_completed_words = auto_complete.find_words(prefix); + + assert_eq!( + auto_completed_words.sort(), + vec!["orange".to_owned(), "oregano".to_owned()].sort() + ); + } +} diff --git a/src/string/mod.rs b/src/string/mod.rs index 0e292330523..f1896f6cafc 100644 --- a/src/string/mod.rs +++ b/src/string/mod.rs @@ -1,5 +1,6 @@ mod aho_corasick; mod anagram; +mod autocomplete_using_trie; mod boyer_moore_search; mod burrows_wheeler_transform; mod duval_algorithm; @@ -18,6 +19,7 @@ mod z_algorithm; pub use self::aho_corasick::AhoCorasick; pub use self::anagram::check_anagram; +pub use self::autocomplete_using_trie::Autocomplete; pub use self::boyer_moore_search::boyer_moore_search; pub use self::burrows_wheeler_transform::{ burrows_wheeler_transform, inv_burrows_wheeler_transform,