|
| 1 | +/** |
| 2 | + * [0676] Implement Magic Dictionary |
| 3 | + * |
| 4 | + * Design a data structure that is initialized with a list of different words. Provided a string, you should determine if you can change exactly one character in this string to match any word in the data structure. |
| 5 | + * Implement the MagicDictionary class: |
| 6 | + * |
| 7 | + * MagicDictionary() Initializes the object. |
| 8 | + * void buildDict(String[] dictionary) Sets the data structure with an array of distinct strings dictionary. |
| 9 | + * bool search(String searchWord) Returns true if you can change exactly one character in searchWord to match any string in the data structure, otherwise returns false. |
| 10 | + * |
| 11 | + * |
| 12 | + * Example 1: |
| 13 | + * |
| 14 | + * Input |
| 15 | + * ["MagicDictionary", "buildDict", "search", "search", "search", "search"] |
| 16 | + * [[], [["hello", "leetcode"]], ["hello"], ["hhllo"], ["hell"], ["leetcoded"]] |
| 17 | + * Output |
| 18 | + * [null, null, false, true, false, false] |
| 19 | + * Explanation |
| 20 | + * MagicDictionary magicDictionary = new MagicDictionary(); |
| 21 | + * magicDictionary.buildDict(["hello", "leetcode"]); |
| 22 | + * magicDictionary.search("hello"); // return False |
| 23 | + * magicDictionary.search("hhllo"); // We can change the second 'h' to 'e' to match "hello" so we return True |
| 24 | + * magicDictionary.search("hell"); // return False |
| 25 | + * magicDictionary.search("leetcoded"); // return False |
| 26 | + * |
| 27 | + * |
| 28 | + * Constraints: |
| 29 | + * |
| 30 | + * 1 <= dictionary.length <= 100 |
| 31 | + * 1 <= dictionary[i].length <= 100 |
| 32 | + * dictionary[i] consists of only lower-case English letters. |
| 33 | + * All the strings in dictionary are distinct. |
| 34 | + * 1 <= searchWord.length <= 100 |
| 35 | + * searchWord consists of only lower-case English letters. |
| 36 | + * buildDict will be called only once before search. |
| 37 | + * At most 100 calls will be made to search. |
| 38 | + * |
| 39 | + */ |
| 40 | +pub struct Solution {} |
| 41 | + |
| 42 | +// problem: https://leetcode.com/problems/implement-magic-dictionary/ |
| 43 | +// discuss: https://leetcode.com/problems/implement-magic-dictionary/discuss/?currentPage=1&orderBy=most_votes&query= |
| 44 | + |
| 45 | +// submission codes start here |
| 46 | + |
| 47 | +#[derive(Debug, Clone)] |
| 48 | +struct TrieNode { |
| 49 | + is_word: bool, |
| 50 | + children: Vec<Option<TrieNode>>, |
| 51 | +} |
| 52 | + |
| 53 | +impl TrieNode { |
| 54 | + fn new() -> Self { |
| 55 | + TrieNode { |
| 56 | + is_word: false, |
| 57 | + children: vec![None; 26], |
| 58 | + } |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +struct MagicDictionary { |
| 63 | + trie: TrieNode, |
| 64 | +} |
| 65 | + |
| 66 | +/** |
| 67 | + * `&self` means the method takes an immutable reference. |
| 68 | + * If you need a mutable reference, change it to `&mut self` instead. |
| 69 | + */ |
| 70 | +impl MagicDictionary { |
| 71 | + fn new() -> Self { |
| 72 | + Self { |
| 73 | + trie: TrieNode::new(), |
| 74 | + } |
| 75 | + } |
| 76 | + fn build_dict(&mut self, dictionary: Vec<String>) { |
| 77 | + for s in &dictionary { |
| 78 | + let mut cur = &mut self.trie; |
| 79 | + for ch in s.as_bytes() { |
| 80 | + if cur.children[(ch - b'a') as usize].is_none() { |
| 81 | + cur.children[(ch - b'a') as usize] = Some(TrieNode::new()); |
| 82 | + } |
| 83 | + cur = cur.children[(ch - b'a') as usize].as_mut().unwrap(); |
| 84 | + } |
| 85 | + cur.is_word = true |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + fn search(&self, mut search_word: String) -> bool { |
| 90 | + fn helper(v: &[u8], trie: &TrieNode) -> bool { |
| 91 | + let mut cur = trie; |
| 92 | + for ch in v { |
| 93 | + if cur.children[(ch - b'a') as usize].is_none() { |
| 94 | + return false; |
| 95 | + } |
| 96 | + cur = cur.children[(ch - b'a') as usize].as_ref().unwrap(); |
| 97 | + } |
| 98 | + cur.is_word |
| 99 | + } |
| 100 | + let mut v = unsafe { search_word.as_bytes_mut() }; |
| 101 | + for i in 0..v.len() { |
| 102 | + for c in b'a'..=b'z' { |
| 103 | + if v[i] == c { |
| 104 | + continue; |
| 105 | + } |
| 106 | + let orig = v[i]; |
| 107 | + v[i] = c; |
| 108 | + if helper(v, &self.trie) { |
| 109 | + return true; |
| 110 | + } |
| 111 | + v[i] = orig; |
| 112 | + } |
| 113 | + } |
| 114 | + false |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +/** |
| 119 | + * Your MagicDictionary object will be instantiated and called as such: |
| 120 | + * let obj = MagicDictionary::new(); |
| 121 | + * obj.build_dict(dictionary); |
| 122 | + * let ret_2: bool = obj.search(searchWord); |
| 123 | + */ |
| 124 | + |
| 125 | +// submission codes end |
| 126 | + |
| 127 | +#[cfg(test)] |
| 128 | +mod tests { |
| 129 | + use super::*; |
| 130 | + |
| 131 | + #[test] |
| 132 | + fn test_0676_example_1() { |
| 133 | + let mut dict = MagicDictionary::new(); |
| 134 | + dict.build_dict(vec!["hello".to_string(), "leetcode".to_string()]); |
| 135 | + assert!(!dict.search("hello".to_string())); |
| 136 | + assert!(dict.search("hhllo".to_string())); |
| 137 | + assert!(!dict.search("hell".to_string())); |
| 138 | + assert!(!dict.search("leetcode".to_string())); |
| 139 | + } |
| 140 | +} |
0 commit comments