LeetCode-208. 实现 Trie (前缀树)-Java-medium

题目链接

法一
/**
 * 前缀树
 * (1)Trie树其实就是维护有公共前缀子串的树
 * (2)利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较
 * 复杂度
 * (1)时间复杂度:初始化为O(1),插入或查找为O(N),N为插入或查找的字符串的长度
 * (2)空间复杂度:O(26*N),N表示Trie结点数量
 */
public class Solution208 {
    /**
     * 前缀树根节点
     */
    private TrieNode root;

    /**
     * 前缀树节点静态内部类
     */
    private static class TrieNode {
        boolean isEnd; // 标记每个单词的结尾
        TrieNode[] children;

        private TrieNode() {
            isEnd = false;
            children = new TrieNode[26]; // 每个节点最多有26个不同的小写字母
        }
    }

    /**
     * 初始化前缀树
     */
    public Solution208() {
        root = new TrieNode(); // 先构造出一个空的根节点
    }

    /**
     * 向前缀树插入单词word
     *
     * @param word
     */
    public void insert(String word) {
        TrieNode cur = root; // 从根节点开始,一直向下走
        for (int i = 0; i < word.length(); i++) { // 单词每个字母正着插
            int c = word.charAt(i) - 'a'; // 将字母用数字表示出来,并作为下标
            if (cur.children[c] == null) {
                cur.children[c] = new TrieNode();
            }
            cur = cur.children[c];
        }
        cur.isEnd = true; // 单词插入完毕,此时cur指向的节点即为该单词的结尾
    }

    /**
     * 判断一个单词word是否完整存在于前缀树中(非递归)
     *
     * @param word
     * @return
     */
    public boolean search(String word) {
        TrieNode cur = root;
        for (int i = 0; i < word.length(); i++) {
            int c = word.charAt(i) - 'a';
            if (cur.children[c] == null) { // 走到了null,说明word不是前缀树的任何一条路径,返回false
                return false;
            }
            cur = cur.children[c];
        }
        return cur.isEnd; // 若cur指向单词末尾,返回true,否则说明word仅仅是一个前缀,并不完整,返回false
    }

    /**
     * 根据word和start得到此时的字符,然后看该字符是否与此时的节点node配对
     *
     * @param word
     * @param node
     * @param start
     * @return
     */
    private boolean match(String word, TrieNode node, int start) {
        if (start == word.length()) {
            return node.isEnd;
        }
        int c = word.charAt(start) - 'a';
        return node.children[c] != null && match(word, node.children[c], start + 1);
    }

    /**
     * 判断一个单词word是否完整存在于前缀树中(递归)
     *
     * @param word
     * @return
     */
    public boolean search_2(String word) {
        return match(word, root, 0);
    }

    /**
     * 判断一个单词word是否是前缀树中的前缀
     *
     * @param prefix
     * @return
     */
    public boolean startsWith(String prefix) {
        TrieNode cur = root;
        for (int i = 0; i < prefix.length(); i++) {
            int c = prefix.charAt(i) - 'a';
            if (cur.children[c] == null) {
                return false;
            }
            cur = cur.children[c];
        }
        return true; // 不关心此时cur是不是指向单词末尾,如果prefix安全走完了,直接返回true即可
    }
}
本地测试
        /**
         * 208. 实现 Trie (前缀树)
         */
        lay.showTitle(208);
        Solution208 sol208 = new Solution208();
        sol208.insert("apple");
        System.out.println(sol208.search("apple")); // 返回 True
        System.out.println(sol208.search("app"));   // 返回 False
        System.out.println(sol208.startsWith("app"));     // 返回 True
        sol208.insert("app");
        System.out.println(sol208.search_2("app"));   // 返回 True
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值