676. Implement Magic Dictionary

2020/01/06 Leetcode

676. Implement Magic Dictionary

Tags: ‘Hash Table’, ‘Trie’

Implement a magic directory with buildDict, and search methods.

For the method buildDict, you'll be given a list of non-repetitive words to build a dictionary.

For the method search, you'll be given a word, and judge whether if you modify exactly one character into another character in this word, the modified word is in the dictionary you just built.

Example 1:

Input: buildDict(["hello", "leetcode"]), Output: Null
Input: search("hello"), Output: False
Input: search("hhllo"), Output: True
Input: search("hell"), Output: False
Input: search("leetcoded"), Output: False

Note:

  1. You may assume that all the inputs are consist of lowercase letters a-z.
  2. For contest purpose, the test data is rather small by now. You could think about highly efficient algorithm after the contest.
  3. Please remember to RESET your class variables declared in class MagicDictionary, as static/class variables are persisted across multiple test cases. Please see here for more details.

Solution

方法1 Build a Trie for searching. 把每一位i的字符替换成a-z其他字符,然后搜索,如果搜到了就return true。

假设字典word平均长度为a,搜索字符长度为N. Trie insert search均为 O(a)

所以buildDict()O(字典总长度)search()O(24*a*N)

O(a) O(24aN) 9% 100%

class MagicDictionary {
    private Trie trie;
    private class Node {
        private Node[] children;
        private boolean isWord;
        private Node() {
            this.children = new Node[26];
        }
    }
    
    private class Trie {
        private Node root;
        private Trie() {
            this.root = new Node();
        }
        
        private void insert(String word) {
            Node p = root;
            for (int i = 0; i < word.length(); i++) {
                int index = (int)(word.charAt(i) - 'a');
                if (p.children[index] == null) {
                    p.children[index] = new Node();
                }
                p = p.children[index];
            }
            p.isWord = true;
        }
        
        private boolean search(String word) {
            Node p = root;
            for (int i = 0; i < word.length(); i++) {
                int index = (int)(word.charAt(i) - 'a');
                if (p.children[index] == null) {
                    return false;
                }
                p = p.children[index];
            }
            return p != null && p.isWord;
        }
    }
    
    public MagicDictionary() {
         this.trie = new Trie();
    }

    public void buildDict(String[] dict) {
        for (String word: dict) {
            trie.insert(word);
        }
    }
    
    public boolean search(String word) {
        for (int i = 0; i < word.length(); i++) {
            char o = word.charAt(i);
            for (char n = 'a'; n <= 'z'; n++) {
                if (n == o) {
                    continue;
                }
                String newWord = word.substring(0, i) + n + word.substring(i+1);
                if (trie.search(newWord)) {
                    return true;
                }
            }
            
        }
        return false;
    }
}

方法2:可以只借鉴前缀树的思路,单纯用一个set存储,search可以降为O(1) 总体search复杂度为O(24*N) 12% 100%

class MagicDictionary {
    private Set<String> set;
    
    public MagicDictionary() {
         this.set = new HashSet<String>();
    }
    
    public void buildDict(String[] dict) {
        for (String word: dict) {
            set.add(word);
        }
    }
    
    public boolean search(String word) {
        for (int i = 0; i < word.length(); i++) {
            char o = word.charAt(i); // 0 -> old char
            for (char n = 'a'; n <= 'z'; n++) { // n -> new char
                if (n == o) {
                    continue;
                }
                String newWord = word.substring(0, i) + n + word.substring(i+1);
                if (set.contains(newWord)) {
                    return true;
                }
            }
            
        }
        return false;
    }
}

Search

    Table of Contents