Trie (Java) - ShuweiLeung/Thinking GitHub Wiki

1.(208:Medium)(非常非常经典题)Implement Trie (Prefix Tree)

  • 前缀树(字典树)是一个非常经典的数据结构,该题考察建造前缀树,在实现过程中,我们将结点定义为含有val,isWord,childern的类,其中val是节点的值,isWord标记从根到当前结点的路径是否能构成单词,children是长度为26的节点类数组。根节点是一个没有val值,只起到索引导向的空值结点。具体实现看下边的代码:
class TrieNode {
    public char val;
    public boolean isWord; 
    public TrieNode[] children = new TrieNode[26];
    public TrieNode() {}
    TrieNode(char c){
        TrieNode node = new TrieNode();
        node.val = c;
    }
}

public class Trie {
    private TrieNode root;
    public Trie() {
        root = new TrieNode();
        root.val = ' ';
    }

    public void insert(String word) {
        TrieNode ws = root;
        for(int i = 0; i < word.length(); i++){
            char c = word.charAt(i);
            if(ws.children[c - 'a'] == null){
                ws.children[c - 'a'] = new TrieNode(c);
            }
            ws = ws.children[c - 'a'];
        }
        ws.isWord = true;
    }

    public boolean search(String word) {
        TrieNode ws = root; 
        for(int i = 0; i < word.length(); i++){
            char c = word.charAt(i);
            if(ws.children[c - 'a'] == null) return false;
            ws = ws.children[c - 'a'];
        }
        return ws.isWord;
    }

    public boolean startsWith(String prefix) {
        TrieNode ws = root; 
        for(int i = 0; i < prefix.length(); i++){
            char c = prefix.charAt(i);
            if(ws.children[c - 'a'] == null) return false;
            ws = ws.children[c - 'a'];
        }
        return true;
    }
}

2.(677:Medium)(非常非常经典题)Map Sum Pairs

  • insert()用来构建线段树,sum()先找到前缀,然后用DFS求和。具体代码参考如下:
    //利用segment tree
    class TrieNode {
        Map<Character, TrieNode> children;
        boolean isWord;
        int value;

        public TrieNode() {
            children = new HashMap<Character, TrieNode>();
            isWord = false;
            value = 0;
        }
    }
    
    TrieNode root;
    
    /** Initialize your data structure here. */
    public MapSum() {
        root = new TrieNode();
    }
    
    public void insert(String key, int val) {
        TrieNode curr = root;
        for (char c : key.toCharArray()) {
            TrieNode next = curr.children.get(c);
            if (next == null) {
                next = new TrieNode();
                curr.children.put(c, next);
            }
            curr = next;
        }
        curr.isWord = true;
        curr.value = val;
    }
    
    public int sum(String prefix) {
        TrieNode curr = root;
	for (char c : prefix.toCharArray()) {
	    TrieNode next = curr.children.get(c);
	    if (next == null) {
	        return 0;
	    }
	    curr = next;
        }
		
        return dfs(curr);
    }
    
    private int dfs(TrieNode root) {
        int sum = 0;
        for (char c : root.children.keySet()) {
            sum += dfs(root.children.get(c));
        }
        return sum + root.value;
    }

3.(1032:Hard)(非常非常经典题)Stream of Characters

  • 该题的关键是反向建立字典树,因为query的过程是需要考虑前面的历史记录的。
    class TrieNode {
        boolean isWord;
        TrieNode[] next = new TrieNode[26];
    }

    TrieNode root = new TrieNode();
    StringBuilder sb = new StringBuilder(); //存储所有query的历史记录

    public _1032_StreamOfCharacters(String[] words) {
        createTrie(words);
    }

    public boolean query(char letter) {
        sb.append(letter); //注意query的时候,是连同前面所有的字符拼接在一起,一起进行单词的查找
        TrieNode node = root;
        for (int i = sb.length() - 1; i >= 0 && node != null; i--) {
            char c = sb.charAt(i);
            node = node.next[c - 'a'];
            if (node != null && node.isWord) {
                return true;
            }
        }
        return false;
    }

    private void createTrie(String[] words) {
        for (String s : words) {
            TrieNode node = root;
            int len = s.length();
            for (int i = len - 1; i >= 0; i--) { //我们反向建树,因为在query的时候,我们是query最前面的k个有效字符,k是有效单词的长度
                char c = s.charAt(i);
                if (node.next[c - 'a'] == null) {
                    node.next[c - 'a'] = new TrieNode();
                }
                node = node.next[c - 'a'];
            }
            node.isWord = true;
        }
    }