[LeetCode 745] Prefix and Suffix Search

Given many wordswords[i] has weight i.

Design a class WordFilter that supports one function, WordFilter.f(String prefix, String suffix). It will return the word with given prefix and suffix with maximum weight. If no word exists, return -1.

Examples:

Input:
WordFilter(["apple"])
WordFilter.f("a", "e") // returns 0
WordFilter.f("b", "") // returns -1

 

Note:

  1. words has length in range [1, 15000].
  2. For each test case, up to words.length queries WordFilter.f may be made.
  3. words[i] has length in range [1, 10].
  4. prefix, suffix have lengths in range [0, 10].
  5. words[i] and prefix, suffix queries consist of lowercase letters only.

 

 

A natrual way of approaching this problem to store all words into a prefix trie and suffix trie separately, then try to find the intersection of all prefix-matched and suffix-matched words. But finding such an intersection can still takes up to O(N) time, N is the total number of words. 

 

Since each word is up to 10 letters, so a much better solution is to insert each word's all possible suffix + a non-letter dividing character + the entire word. This way each time we do a query, we can simply concatenate the suffix with divider character + prefix to get a new prefix word and perform a prefix search in a prefix trie. 

 

'{' is right after 'z', so we can pick it as the divider to make our implementation easier. 

 

To insert all words plus their variations into a prefix trie, it takes O(N * K^2) time, N is the total number of words, K is the average length of each word. Each query takes O(K) time.

The space is O(N * K^2). This is the worst case, the more shared prefix and suffix we have, the less space it consumes.

 

 

class WordFilter {
    private class TrieNode {
        char c;
        TrieNode[] child;
        int weight;
        
        TrieNode(char c) {
            this.c = c;
            this.child = new TrieNode[27];
            this.weight = -1;
        }
    }
    private class Trie {
        TrieNode root;
        Trie() {
            this.root = new TrieNode('#');
        }
        void insert(String word, int w) {
            TrieNode curr = root;
            for(int i = 0; i < word.length(); i++) {
                int d = word.charAt(i) - 'a';
                if(curr.child[d] == null) {
                    curr.child[d] = new TrieNode(word.charAt(i));
                }
                curr.child[d].weight = w;
                curr = curr.child[d];
            }                
        }
        int getMaxWeight(String prefix) {
            TrieNode curr = root;
            int maxWeight = -1;
            for(int i = 0; i < prefix.length(); i++) {
                int d = prefix.charAt(i) - 'a';
                if(curr.child[d] == null) {
                    return -1;
                }
                curr = curr.child[d];
                maxWeight = curr.weight;
            }
            return maxWeight;
        }
    }
    private Trie trie;
    public WordFilter(String[] words) {
        trie = new Trie();
        for(int i = 0; i < words.length; i++) {
            for(int j = 0; j <= words[i].length(); j++) {
                trie.insert(words[i].substring(j) + "{" + words[i], i);
            }
        }
    }
    
    public int f(String prefix, String suffix) {
        return trie.getMaxWeight(suffix + "{" + prefix);
    }
}

/**
 * Your WordFilter object will be instantiated and called as such:
 * WordFilter obj = new WordFilter(words);
 * int param_1 = obj.f(prefix,suffix);
 */

 

posted @ 2020-05-27 06:54  Review->Improve  阅读(287)  评论(0编辑  收藏  举报