前缀树

时间复杂度与数据量无关,与样本长度有关。
在这里插入图片描述

  • 每个节点保存三个数据:
    path: 有多少节点滑过
    end: 多少节点以当前字符结束
    TrieNode[] nexts: 链接数组,链接的索引隐式地定义了对应地字符。
    链接数组保存了下一个节点的链接。
    JAVA代码
public class TrieTree {
    /***************定义节点结构*******************/
    public static class TrieNode{
        public int path;
        public int end;
        public TrieNode[] nexts;
        public TrieNode(){
            path = 0;   //扫过该字母的次数:用于求相同前缀的单词数量
            end = 0;   //以该字母结束的单词数:用于求单词数量/单词是否存在/删除单词
            nexts = new TrieNode[26];
        }
    }
    public static class Trie{
        private TrieNode root;
        public Trie(){
            root = new TrieNode();
        }
        /********************插入单词********************/
        public void insert(String word){  //插入单词
            if (word==null) return;
            TrieNode node = root;
            char[] chs = word.toCharArray();
            for (int i=0; i<chs.length; i++){
                int index = chs[i]-'a';
                if (node.nexts[index] ==null ){
                    node.nexts[index] = new TrieNode();
                }
                node = node.nexts[index];
                node.path++;
            }
            node.end++;
        }

        /******************查找某个单词出现过多少次*********************/
        public int search(String word){  //找有几个该单词
            if (word == null) return 0;
            TrieNode node = root;
            char[] chs = word.toCharArray();
            for (int i=0; i<chs.length; i++){
                int index = chs[i]-'a';
                if (node.nexts[index] != null){
                    node = node.nexts[index];
                }else{
                    return 0;
                }
            }
            return node.end;
        }
        /****************删除单词****************/
        public void delete(String word){
            if (search(word)!=0) { //确定树中存在该单词
                TrieNode node = root;
                char[] chs = word.toCharArray();
                for (int i = 0; i < chs.length; i++) {
                    int index = chs[i] - 'a';
                    if (--node.nexts[index].path == 0) {  //path减到0了,后面的链接直接删除
                        node.nexts[index] = null;
                        return;
                    }
                    node = node.nexts[index];
                }
                node.end--;
            }
        }
        /*********************某相同前缀的单词有多少个**********************/
        public int prefixNumber(String pre){
            int count = 0;
            if (pre == null) return count;
                TrieNode node = root;
                char[] chs = pre.toCharArray();
                for (int i=0; i<chs.length; i++){
                    int index = chs[i] - 'a';
                    if (node.nexts[index]==null){  //不存在该前缀,返回0
                        return 0;
                    }
                    node = node.nexts[index];
                }
                return node.path;
        }
    }
}

leetcode 208. 实现 Trie (前缀树)

实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
示例:

Trie trie = new Trie();

trie.insert("apple");
trie.search("apple");   // 返回 true
trie.search("app");     // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");   
trie.search("app");     // 返回 true

题解:
前缀树结构。
只有插入、查找、找前缀。因此可如下设置前缀树节点结构:
boolean end: 是否有单词以当前字符结束
TrieNode[] nexts: 链接数组。
JAVA代码

class Trie {
    /** Initialize your data structure here. */
    //定义前缀树节点结构
    public static class TrieNode{
        public boolean end;
        public TrieNode[] nexts;
        public TrieNode(){
            end = false;
            nexts = new TrieNode[26];
        }
    }
    
    TrieNode root;
    public Trie() {
        root = new TrieNode();
    }
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        if (word == null) return;
        TrieNode node = root;
        char[] chs = word.toCharArray();
        for (int i = 0; i< chs.length; i++){
            int index = chs[i]-'a';
            if (node.nexts[index] == null){
                node.nexts[index] = new TrieNode();
            }
            node = node.nexts[index];
        }
        node.end = true;
    }
    
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        if (word == null) return false;
        TrieNode node = root;
        char[] chs = word.toCharArray();
        for (int i=0; i<chs.length; i++){
            int index = chs[i]-'a';
            if (node.nexts[index] == null){
                return false;
            }
            node = node.nexts[index];
        }
        if (node.end == false) return false;
        return true;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        if (prefix == null) return false;
        TrieNode node = root;
        char[] chs = prefix.toCharArray();
        for(int i=0; i<chs.length; i++){
            int index = chs[i] - 'a';
            if (node.nexts[index] == null){
                return false;
            }
            node = node.nexts[index];
        }
        return true;
    }
}

/**
 * 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);
 */

677. 键值映射

实现一个 MapSum 类里的两个方法,insert 和 sum。
对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。
对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。

示例 1:

输入: insert("apple", 3), 输出: Null
输入: sum("ap"), 输出: 3
输入: insert("app", 2), 输出: Null
输入: sum("ap"), 输出: 5

题解:

class MapSum {

    /** Initialize your data structure here. */
    public static class TrieNode{
        public int val;   
        public TrieNode[] nexts;
        public TrieNode(){
            val = 0;  
            nexts = new TrieNode[26];
        }
    }
    
    TrieNode root;
    public MapSum() {
        root = new TrieNode();
    }
    
    public void insert(String key, int val) {
        if (key == null) return;
        char[] chs = key.toCharArray();
        TrieNode node = root;
        for (int i=0; i<chs.length; i++){
            int index = chs[i]-'a';
            //若不存在该单词,创建新的节点路径
            if (node.nexts[index]==null){
                node.nexts[index] = new TrieNode();
            }
            node = node.nexts[index];
        }
        //下面两句包含两层含义:
        //1. 若不存在该单词,直接创建一个新的路径
        //2. 若已存在该单词,原来的键值替代成新的键值
        node.val = val;   
    } 
    public int sum(String prefix) {
        int num = 0;
        if (prefix == null) return 0;
        char[] chs = prefix.toCharArray();
        TrieNode node = root;
        for (int i=0; i<chs.length;i++){
            int index = chs[i] - 'a';
            if(node.nexts[index] == null){
                return 0;
            }
            node = node.nexts[index];
        }  
        return dfs(node);
    }
    
    //深度优先遍历当前节点后面的所有TrieNode, 累加val值
    public int dfs(TrieNode node){
        int num = 0;
        if (node==null) return num;
        num += node.val;
        for (TrieNode curr: node.nexts){
            num += dfs(curr);
        }
        return num;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值