字典树 前缀树

字典树是一种数据结构,也叫前缀树、Trie树。比较常用的应用有前缀匹配和词频统计。其特点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。Trie的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

浏览器的搜索算法就是字典树的一种典型应用:
在这里插入图片描述

字典树的特性

  • 根节点不包含字符,除了根节点其他每个节点都只包含一个字符。根节点不包含字符的目的是为了能包括所有字符串。
  • 从根节点到每一个节点,经过的字符串起来就是该节点对应的字符串。
  • 每个节点的所有子节点包含的字符都不相同。
    在这里插入图片描述

java实现字典树

LeetCode208题

定义根节点的结构体

root节点的结构体中包含一个长度为26的数组,代表’a’~‘z’。boolean类型变量isEnd表示是否为字符串末尾。

有的场景还会添加一个String类型的变量,用于存储从根节点到此节点串成的字符串。

    class TrieNode {
        TrieNode[] children = new TrieNode[26];
        boolean isEnd = false;
    }

Trie初始化

public class Trie {
    TrieNode root;

    public Trie() {
        root = new TrieNode();
    }
}

insert方法

insert方法用于向字典树中插入字符串word。

    public void insert(String word) {
        TrieNode tmp = root;
        for (char c : word.toCharArray()) {
            int index = c - 'a';
            if (tmp.children[index] == null) {
                tmp.children[index] = new TrieNode();
            }
            tmp = tmp.children[index];
        }
        tmp.isEnd = true;
    }

search方法

search方法用于查询字典树中是否存在字符串word。除了要判断字典树中word开头的字符串是否存在,还需要判断isEnd。

    public boolean search(String word) {
        TrieNode tmp = root;
        for (char c : word.toCharArray()) {
            int index = c - 'a';
            if (tmp.children[index] == null) {
                return false;
            }
            tmp = tmp.children[index];
        }
        return tmp.isEnd;
    }

startsWith方法

startsWith方法用于判断字典树中是否存在prefix开头的字符串,存在返回true,不存在则返回false。

    public boolean startsWith(String prefix) {
        TrieNode tmp = root;
        for (char c : prefix.toCharArray()) {
            int index = c - 'a';
            if (tmp.children[index] == null) {
                return false;
            }
            tmp = tmp.children[index];
        }
        return true;
    }

LeetCode练习题

720. 词典中最长的单词

    public String longestWord(String[] words) {
        Trie trie = new Trie();
        for (String word : words) {
            trie.insert(word);
        }
        String longest = "";
        for (String word : words) {
            if (!trie.search(word)) {
                continue;
            }
            if (longest.length() < word.length()) {
                longest = word;
            } else if (longest.length() == word.length() && longest.compareTo(word) > 0) {
                longest = word;
            }
        }
        return longest;
    }

    class Trie {
        class TrieNode {
            TrieNode[] children = new TrieNode[26];
            boolean isEnd = false;
        }

        TrieNode root = new TrieNode();

        public void insert(String word) {
            TrieNode tmp = root;
            for (char c : word.toCharArray()) {
                int index = c - 'a';
                if (tmp.children[index] == null) {
                    tmp.children[index] = new TrieNode();
                }
                tmp = tmp.children[index];
            }
            tmp.isEnd = true;
        }

        public boolean search(String word) {
            TrieNode tmp = root;
            for (char c : word.toCharArray()) {
                int index = c - 'a';
                if (tmp.children[index] == null) {
                    return false;
                }
                // 区别于208题的地方。
                // 因为判断的word必须是由其他字符串在末尾加上一位组成,
                // 因此树中必须存在1~len-1位的字符串,且这些字符串也都满足这个要求
                if (!tmp.children[index].isEnd) {
                    return false;
                }
                tmp = tmp.children[index];
            }
            return tmp.isEnd;
        }
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值