trie(前缀树)

trie(前缀树)

问题描述

给你10000个字符串集,如何快速判断一个字符串在没在这字符串集中?

解决思路

  • 如果使用最傻的遍历整个集合,时间复杂度O(n^2),显然不可行,时间复杂度太大
  • 使用trie树,它的特点是:
    • 核心思想:用空间换时间
    • 使用字符串的公共前缀,节省查找时间
    • 定义一个头节点,判断是否有走向某个节点的路,(这块的路代表的是节点的指向)

构建一棵前缀树

扩充内容

  • 我还想知道有多少字符串是以"be"开始的?
  • 某个字符串被加了多少次?

思路:

  • 给节点设置个属性,path 表示经过节点多少次,就可以判断前缀为"be"的字符串有多少个
  • 给节点一个属性,end 表示这条链被加入多少次

代码实现

package com.sparrow.zg.tree;

/**
 * 前缀树
 */
public class TrieTree {
    public static class TreeNode {
        public int path;
        public int end;
        public TreeNode[] nexts;

        public TreeNode() {
            path = 0;
            end = 0;
            nexts = new TreeNode[26];//当前节点只能接受a~b
        }
    }

    /**
     * 前缀树:
     * 1.查n个字符传中有多少个以**开始的
     */
    public static class Trie {
        private TreeNode root;

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

        public void insert(String word) {
            if (word == null) {
                return;
            }
            char[] chs = word.toCharArray();
            int index = 0;
            TreeNode node = root;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (node.nexts[index] == null) {
                    node.nexts[index] = new TreeNode();
                }
                node = node.nexts[index];
                node.path++;
            }
            node.end++;
        }

        /**
         * 查找某个字串被添加多少次
         *
         * @param word 查询的字串
         * @return 被添加的次数
         */
        public int search(String word) {
            if (word == null) {
                return 0;
            }
            char[] chs = word.toCharArray();
            TreeNode node = root;
            int index = 0;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (node.nexts[index] == null) {
                    return 0;
                }
                node = node.nexts[index];
            }
            return node.end;
        }

        /**
         * 记录多少字符串是以word开头的
         *
         * @param word 前缀字符串
         * @return 字符串的个数
         */
        public int prefixNumber(String word) {
            if (word == null) {
                return 0;
            }
            char[] chs = word.toCharArray();
            int index = 0;
            TreeNode node = root;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (node.nexts[index] == null) {
                    return 0;
                }
                node = node.nexts[index];
            }
            return node.path;
        }

        /**
         * 删除对应的字符串
         *
         * @param word 要删除的字符串
         */
        public void delete(String word) {
            if (word == null) {
                return;
            }
            if (search(word) == 0) {
                return;
            }
            char[] chs = word.toCharArray();
            int index;
            TreeNode node = root;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (--node.nexts[index].path == 0) {//如果当前节点指向的节点的path==0,说明下面节点只走过一次
                    node.nexts[index] = null;//将下个节点的指向空
                    return;
                }
                node = node.nexts[index];
            }
            node.end--;
        }
    }

参考资料

Trie(前缀树/字典树)及其应用

猜你喜欢

转载自www.cnblogs.com/sparrowzg/p/10526028.html