• 【树】实现前缀树


    题目描述

    前缀树是一种树形结构,用于高效的存储和检索字符串。请实现字符串,要求如下:

    1. Trie() 初始化前缀树对象。
    2. void insert(String word) 向前缀树中插入字符串 word 。
    3. boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
    4. boolean startsWith(String prefix) 如果之前已经插入的字符串word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

    示例: 

    输入
    ["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
    [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
    输出
    [null, null, true, false, true, null, true]

    解释
    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

    解法思路 

    构造节点

    字符长度是26,使用一个长为26的数组做处理。那么字符'a'所在位置就是0='a'-'a',字符'p'所在位置就是'p'-'a'; 

    考虑方法search(word),这个方法要求word在前缀树中,并且word的最后一个字符也能在前缀树中找到并且也是最后一个字符。这里我参考了其他人的实现,需要增加一个标志符是否是结尾字符。

    通过上述信息,可以确定单个节点的数据结构:


        class Node {
            boolean end;
            Node[] nodes;

            public Node() {
                this.nodes = new Node[26];
                this.end = false;
            }
        }


    完成insert方法

    insert操作时,用户传入word,那么需要处理每个字符。

    1. 首先,查找这个字符的 int index=word.charAt(i)-'a' ;
    2. 找到这个字符所在位置,如果不存在下一个节点,则新建一个节点;如果存在下一个节点,则继续执行。
    3. 最后将最后一个字符对应的节点的属性end设置成true

    这样可以得到如下代码:

        public void insert(String word) {
            Node temp = root;
            for (char c : word.toCharArray()) {
                if (temp.nodes[c - 'a'] == null) {
                    temp.nodes[c - 'a'] = new Node();
                }
                temp = temp.nodes[c - 'a'];
            }
            temp.end = true;
        }


    完成search方法

    search执行时,用户传入word进行全字符匹配,这个时候参考insert操作;判断条件做出调整:

    1. 如果还没有遍历完成,有节点为NULL,则直接返回false;
    2. 如果遍历完成,则判断最后的节点的end是否为true;

    这样有代码如下:

        public boolean search(String word) {
            Node temp = root;
            for (char c : word.toCharArray()) {
                if (temp.nodes[c - 'a'] == null) {
                    return false;
                }
                temp = temp.nodes[c - 'a'];
            }
            return temp.end;
        }


    完成startsWith方法

    执行startsWith则只需要保证有字符能匹配即可,参考search代码,

    1. 如果还没有遍历完成,有节点为NULL,则直接返回false;
    2. 遍历完成,则直接返回true。

    那么具体代码实现如下:

        public boolean startsWith(String prefix) {
            Node temp = root;
            for (char c : prefix.toCharArray()) {
                if (temp.nodes[c - 'a'] == null) {
                    return false;
                }
                temp = temp.nodes[c - 'a'];
            }
            return true;
        }

    代码实现 

    1. class Trie {
    2. Node root;
    3. public Trie() {
    4. this.root = new Node();
    5. }
    6. public void insert(String word) {
    7. Node temp = root;
    8. for (char c : word.toCharArray()) {
    9. if (temp.nodes[c - 'a'] == null) {
    10. temp.nodes[c - 'a'] = new Node();
    11. }
    12. temp = temp.nodes[c - 'a'];
    13. }
    14. temp.end = true;
    15. }
    16. public boolean search(String word) {
    17. Node temp = root;
    18. for (char c : word.toCharArray()) {
    19. if (temp.nodes[c - 'a'] == null) {
    20. return false;
    21. }
    22. temp = temp.nodes[c - 'a'];
    23. }
    24. return temp.end;
    25. }
    26. public boolean startsWith(String prefix) {
    27. Node temp = root;
    28. for (char c : prefix.toCharArray()) {
    29. if (temp.nodes[c - 'a'] == null) {
    30. return false;
    31. }
    32. temp = temp.nodes[c - 'a'];
    33. }
    34. return true;
    35. }
    36. class Node {
    37. boolean end;
    38. Node[] nodes;
    39. public Node() {
    40. this.nodes = new Node[26];
    41. this.end = false;
    42. }
    43. }
    44. public static void main(String[] args) {
    45. Trie trie = new Trie();
    46. trie.insert("apple");
    47. System.out.println(trie.search("apple"));
    48. System.out.println(trie.search("app"));
    49. System.out.println(trie.startsWith("app"));
    50. trie.insert("app");
    51. System.out.println(trie.search("app"));
    52. }
    53. }

    总结

    这道题是对前缀树的实现,核心是考虑清楚如何构造前缀树的节点。这里我们使用了一个空NODE作为root节点,方便后续的操作。耗时和空间上应该还可以优化,有好的方案欢迎评论,大家一起探讨。

  • 相关阅读:
    ssm大型商场移动导游系统的设计与实现毕业设计源码100853
    hdc_std安装配置以及常用命令
    C++学习第二十八天----引用变量的特别之处
    ssh服务
    访问url 404 的错误
    神经网络层次分析模型,神经网络层次分析方法
    Springcloud可视化物联网智慧工地云SaaS平台源码 支持二开和私有化部署
    工业数字化与新一代数字化系统设计平台----讲座
    HTML做一个节日页面【六一儿童节】纯HTML代码
    Java 基础面试300题 (201-230)
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126132337