树的理解(五):Trie

Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。

实现 Trie (前缀树)

https://leetcode-cn.com/problems/implement-trie-prefix-tree/

二叉树的每个节点存放两个指针,left指向左子树的头结点,right指向了右子树的头结点,这两个指针都为Node类型;
相对于二叉树,前缀树的节点也要存指针,指向其他子节点。那么对于这种类型的指针该如何设计呢,如果是要设计与字符串相关的前缀树(假设字符的范围为a-z),Node类中只需要维护一个指针数组,大小为26(对应26个英文字母),该数组也是Node类型,用来子节点的指针,很明显,前缀树是一个多叉树。
除了指针外,还要维护一个类型为boolean的变量,来判断节点是否为叶子节点。

那么对于前缀树的insert方法来说,不需要真正的插入字符串每个字符的值,只需要在每个节点中将字符所对应下标的位置上插入一个新的节点,就可以表示存在该字符,在前缀树表示的字符串最后的一个字符中,要将isLeaf变量设为true,表示字符串到此结束。

对于search方法来说,逐一判断前缀树中是否存在字符串的所有字符即可,如果前缀树中所对应字符串指定字符的节点为null,那么表示不存在该字符串,直到判断字符串的最后一个字符,并判断isLeaf是否为true。(表示字符串结束)

对于startsWith方法来说,逐一判断前缀树中是否存在字符串的所有字符即可,如果前缀树中所对应字符串指定字符的节点为null,那么表示不存在该字符串,直到判断字符串的最后一个字符即可。无需判断isLeaf。

class Trie {

    private class Node{
        Node[] childs = new Node[26];
        boolean isLeaf;
    }

    private Node root = new Node();

    /** Initialize your data structure here. */
    public Trie() {}
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        insert(word,root);
    }
    private void insert(String word,Node node) {
        if(node == null) return;
        if(word.length() == 0) {
            node.isLeaf = true;
            return;
        }
        int index = findCharIndex(word.charAt(0));
        if(node.childs[index] == null) 
            node.childs[index] = new Node();
        insert(word.substring(1),node.childs[index]);        
    }
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        return search(word,root);
    }

    private boolean search(String word,Node node) {
        if(node == null) return false;
        if(word.length() == 0) return node.isLeaf;
        int index = findCharIndex(word.charAt(0));
        return search(word.substring(1),node.childs[index]);
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        return startsWith(prefix,root);
    }
    private boolean startsWith(String prefix,Node node) {
        if(node == null) return false;
        if(prefix.length() == 0) return true;
        int index = findCharIndex(prefix.charAt(0));
        return startsWith(prefix.substring(1),node.childs[index]);
    }
    //找到指定字符在节点中的index
	private int findCharIndex(char c) {
        return c - 'a';
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */

键值映射

https://leetcode-cn.com/problems/map-sum-pairs/

思路和上面差不多,Node节点中维护一个值val

class MapSum {

    private class Node {
        Node[] childs = new Node[26];
        int val;
    }
    private Node root = new Node();
    /** Initialize your data structure here. */
    public MapSum() {

    }
    
    public void insert(String key, int val) {
        insert(key,val,root);
    }
    private void insert(String key,int val,Node node) {
        if(node == null) return;
        if(key.length() == 0) {
            node.val = val;
            return;
        }
        int index = findCharIndex(key.charAt(0));
        if(node.childs[index] == null)  //一定要加这个判断,否则会将旧值覆盖
            node.childs[index] = new Node();
        insert(key.substring(1),val,node.childs[index]);
    }
    private int findCharIndex(char c) {
        return c - 'a';
    }
    
    public int sum(String prefix) {
        
        return sum(prefix,root);
    }
    private int sum(String prefix, Node node) {
        if (node == null) return 0;
        if (prefix.length() != 0) {
            int index = findCharIndex(prefix.charAt(0));
            return sum(prefix.substring(1), node.childs[index]);
        }
        int sum = node.val;
        for (Node child : node.childs) {
            sum += sum(prefix, child);
        }
        return sum; 
    }
}
发布了352 篇原创文章 · 获赞 73 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43777983/article/details/105239636
今日推荐