-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdesign_add_and_search_words_data_structure.rs
105 lines (89 loc) · 2.98 KB
/
design_add_and_search_words_data_structure.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use std::collections::HashMap;
struct TrieNode {
value: char,
items: HashMap<char, TrieNode>,
ends_at: bool,
}
impl TrieNode {
fn new(value: char) -> Self {
TrieNode { value, items: HashMap::new(), ends_at: false }
}
}
/// Design a data structure that supports adding new words and finding if a string matches any
/// previously added string.
///
/// Implement the `WordDictionary` class:
///
/// * `WordDictionary()` Initializes the object.
///
/// * `void addWord(word)` Adds `word` to the data structure, it can be matched later.
///
/// * `bool search(word)` Returns `true` if there is any string in the data structure that matches
/// `word` or `false` otherwise. `word` may contain dots `'.'` where dots can be matched with any
/// letter.
struct WordDictionary {
root: TrieNode,
}
impl WordDictionary {
fn new() -> Self {
Self { root: TrieNode::new('*') }
}
fn add_word(&mut self, word: String) {
let mut current: &mut TrieNode = &mut self.root;
for letter in word.chars() {
if current.items.contains_key(&letter) {
current = current.items.get_mut(&letter).unwrap();
} else {
let node = TrieNode::new(letter);
current.items.insert(letter, node);
current = current.items.get_mut(&letter).unwrap();
}
}
current.ends_at = true;
}
fn search(&self, word: String) -> bool {
let letters: Vec<char> = word.chars().collect();
Self::search_worker(&self.root, &letters, 0)
}
fn search_worker(node: &TrieNode, letters: &Vec<char>, i: usize) -> bool {
let n = letters.len();
let letter = letters[i];
let mut result = false;
if letter == '.' {
for value in node.items.values() {
if i == n-1 {
result = result || value.ends_at;
} else {
result = result || Self::search_worker(value, letters, i+1);
}
}
} else if node.items.contains_key(&letter) {
let value = &node.items[&letter];
if i == n-1 {
result = value.ends_at;
} else {
result = Self::search_worker(value, letters, i+1);
}
}
result
}
}
#[cfg(test)]
mod tests {
use super::WordDictionary;
#[test]
fn example_1() {
let mut word_dictionary = WordDictionary::new();
word_dictionary.add_word("bad".to_string());
word_dictionary.add_word("dad".to_string());
word_dictionary.add_word("mad".to_string());
let result = word_dictionary.search("pad".to_string());
assert!(!result);
let result = word_dictionary.search("bad".to_string());
assert!(result);
let result = word_dictionary.search(".ad".to_string());
assert!(result);
let result = word_dictionary.search("b..".to_string());
assert!(result);
}
}