Skip to content

Commit 6163515

Browse files
committed
Added prefix trie, eliminated Clippy warnings
1 parent 88b0d6f commit 6163515

File tree

4 files changed

+67
-15
lines changed

4 files changed

+67
-15
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
target
1+
target/
2+
**/*.rs.bk
3+
Cargo.lock

src/graph/dfs.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ impl<'a> Iterator for DfsIterator<'a> {
3838
// https://www.geeksforgeeks.org/iterative-depth-first-traversal/
3939
// https://en.wikipedia.org/wiki/Depth-first_search
4040
while let Some(&s) = self.stack.last() {
41-
4241
//Does s still have neighbors we need to process?
43-
if let Some((_,s_nbr)) = self.adj_iters[s].next() {
42+
if let Some((_, s_nbr)) = self.adj_iters[s].next() {
4443
if !self.visited[s_nbr] {
4544
self.stack.push(s_nbr);
4645
}
@@ -109,13 +108,13 @@ mod test {
109108
let mut dfs_check = vec![];
110109
for _ in 0..num_v {
111110
dfs_check.push(dfs_search.next().unwrap());
112-
assert!(dfs_search.stack.len() <= num_v+1);
111+
assert!(dfs_search.stack.len() <= num_v + 1);
113112
}
114113

115114
dfs_check.sort();
116115
dfs_check.dedup();
117116
assert_eq!(0, dfs_check[0]);
118117
assert_eq!(num_v, dfs_check.len());
119-
assert_eq!(num_v-1, dfs_check[num_v-1]);
118+
assert_eq!(num_v - 1, dfs_check[num_v - 1]);
120119
}
121120
}

src/math.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,28 @@ pub fn mod_pow(mut base: u64, mut exp: u64, m: u64) -> u64 {
1717
result
1818
}
1919

20-
/// Finds (d, x, y) such that d = gcd(a, b) = ax + by.
20+
/// Finds (d, coef_a, coef_b) such that d = gcd(a, b) = a * coef_a + b * coef_b.
2121
pub fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
2222
if b == 0 {
2323
(a.abs(), a.signum(), 0)
2424
} else {
25-
let (d, x, y) = extended_gcd(b, a % b);
26-
(d, y, x - y * (a / b))
25+
let (d, coef_a, coef_b) = extended_gcd(b, a % b);
26+
(d, coef_b, coef_a - coef_b * (a / b))
2727
}
2828
}
2929

30-
/// Assuming a != 0, finds smallest y >= 0 such that ax + by = c.
30+
/// Assuming a != 0, finds smallest coef_b >= 0 such that a * coef_a + b * coef_b = c.
3131
///
3232
/// # Panics
3333
///
3434
/// Panics if a == 0.
3535
pub fn canon_egcd(a: i64, b: i64, c: i64) -> Option<(i64, i64, i64)> {
36-
let (d, _, yy) = extended_gcd(a, b);
36+
let (d, _, coef_b_init) = extended_gcd(a, b);
3737
if c % d == 0 {
38-
let z = (a / d).abs();
39-
let y = (yy * (c / d) % z + z) % z;
40-
let x = (c - b * y) / a;
41-
Some((d, x, y))
38+
let a_d = (a / d).abs();
39+
let coef_b = (coef_b_init * (c / d) % a_d + a_d) % a_d;
40+
let coef_a = (c - b * coef_b) / a;
41+
Some((d, coef_a, coef_b))
4242
} else {
4343
None
4444
}

src/string_proc.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl SuffixArray {
9090
/// Suffix array construction in O(n log n) time.
9191
pub fn new(text: &[u8]) -> Self {
9292
let n = text.len();
93-
let init_rank = text.into_iter().map(|&ch| ch as usize).collect::<Vec<_>>();
93+
let init_rank = text.iter().map(|&ch| ch as usize).collect::<Vec<_>>();
9494
let mut sfx = Self::counting_sort(0..n, &init_rank, 256);
9595
let mut rank = vec![init_rank];
9696
// Invariant at the start of every loop iteration:
@@ -137,6 +137,39 @@ impl SuffixArray {
137137
}
138138
}
139139

140+
/// Prefix trie
141+
#[derive(Default)]
142+
pub struct Trie<K: std::hash::Hash + Eq> {
143+
count: usize,
144+
branches: std::collections::HashMap<K, Trie<K>>,
145+
}
146+
147+
impl<K: std::hash::Hash + Eq + Default> Trie<K> {
148+
/// Inserts a word into the trie.
149+
pub fn insert(&mut self, word: impl IntoIterator<Item = K>) {
150+
let mut node = self;
151+
node.count += 1;
152+
153+
for ch in word {
154+
node = { node }.branches.entry(ch).or_insert_with(Default::default);
155+
node.count += 1;
156+
}
157+
}
158+
159+
/// Computes the number of inserted words that start with the given prefix.
160+
pub fn get(&self, prefix: impl IntoIterator<Item = K>) -> usize {
161+
let mut node = self;
162+
163+
for ch in prefix {
164+
match node.branches.get(&ch) {
165+
Some(sub) => node = sub,
166+
None => return 0,
167+
}
168+
}
169+
node.count
170+
}
171+
}
172+
140173
/// Manacher's algorithm for computing palindrome substrings in linear time.
141174
/// pal[2*i] = odd length of palindrome centred at text[i].
142175
/// pal[2*i+1] = even length of palindrome centred at text[i+0.5].
@@ -208,6 +241,24 @@ mod test {
208241
}
209242
}
210243

244+
#[test]
245+
fn test_trie() {
246+
let dict = vec!["banana", "benefit", "banapple", "ban"];
247+
248+
let trie = dict.into_iter().fold(Trie::default(), |mut trie, word| {
249+
Trie::insert(&mut trie, word.bytes());
250+
trie
251+
});
252+
253+
assert_eq!(trie.get("".bytes()), 4);
254+
assert_eq!(trie.get("b".bytes()), 4);
255+
assert_eq!(trie.get("ba".bytes()), 3);
256+
assert_eq!(trie.get("ban".bytes()), 3);
257+
assert_eq!(trie.get("bana".bytes()), 2);
258+
assert_eq!(trie.get("banan".bytes()), 1);
259+
assert_eq!(trie.get("bane".bytes()), 0);
260+
}
261+
211262
#[test]
212263
fn test_palindrome() {
213264
let text = "banana".as_bytes();

0 commit comments

Comments
 (0)