关于前缀树的一些题目

关于前缀树的一些题目

1、实现前缀树

  • 描述:

    ​ 请你实现 Trie 类:

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

  • 解法:

    ​ 1、构造字典树:包含以下两个字段:

    • 指向子节点的指针数组 son。对于本题而言,数组长度为26,即小写英文字母的数量。此时 son[0] 对应小写字母 a,son[1] 对应小写字母 b,…,son[25] 对应小写字母 z。

    • 布尔字段 isEnd,表示该节点是否为字符串的结尾。

      2、插入函数:

    • 当插入一个字符时,如果这个字符不存在,就在当前节点的 son 数组中加入一个新的节点。

    • 如果存在,就继续向下遍历下一个字符。

      3、搜索字符串:

    • 对当前字符串的每一个字符进行遍历,如果字典树中含有这个字符,就继续下一个字符,直到字符串结束或者前缀树当前节点 isEnd 为 true

    • 如果不含这个字符,就直接 return false;

      4、搜索前缀:

    • 与搜索字符差不多,只要求含有这个前缀就好了,不是完全符合。

  • 源码:

    class Trie {
    private Trie[] son;
    private boolean isEnd;
    /** Initialize your data structure here. */
    public Trie() {
    son = new Trie[26];
    isEnd = false;
    }
    /** Inserts a word into the trie. */
    public void insert(String word) {
    Trie node = this;
    for(int i=0; i<word.length(); i++){
    int index = word.charAt(i)-'a';
    if(node.son[index] == null){
    node.son[index] = new Trie();
    }
    node = node.son[index];
    }
    node.isEnd = true;
    }
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
    Trie node = searchWord(word);
    //有不相等 或者 未到结尾都是 false
    return node!=null && node.isEnd;
    }
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
    //未到结尾也可以
    return (searchWord(prefix)!=null);
    }
    /*搜索函数本体*/
    public Trie searchWord(String word){
    Trie node = this;
    for(int i=0; i<word.length(); i++){
    int index = word.charAt(i)-'a';
    //不相等了,就是有不相等的字符在 word 遍历完之前
    if(node.son[index] == null){
    return null;
    }
    node = node.son[index];
    }
    return node;
    }
    }

2、替换单词

  • 描述:

    ​ 在英语中,我们有一个叫做 词根(root) 的概念,可以词根后面添加其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。

    现在,给定一个由许多词根组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。

    你需要输出替换之后的句子。

  • 解法:

    ​ 有了上题的经验,很容易想到使用前缀树为提供的词根建立前缀树,但是这里一个词根结束的标记,我们不能再使用 isEnd 来标记。如果结果是以词根开头的话,我们要取得词根本身,而不是一个结束标记。所以这里使用一个字符串来标记结束。

  • 源码:

    class Solution {
    private TrieNode root = new TrieNode();
    public String replaceWords(List<String> dictionary, String sentence) {
    //将字典插入树
    for(int i=0; i<dictionary.size(); i++){
    String str = dictionary.get(i);
    TrieNode node = root;
    for(int j=0; j<str.length(); j++){
    int index = str.charAt(j)-'a';
    if(node.son[index] == null){
    node.son[index] = new TrieNode();
    }
    node = node.son[index];
    }
    //把完整的词根加进叶子节点
    node.word = str;
    }
    //对 sentence 进行遍历
    StringBuilder res = new StringBuilder();
    for(String s : sentence.split("\\s+")){
    if(res.length()>0) res.append(" ");
    TrieNode node = root;
    for(int i=0; i<s.length(); i++){
    int index = s.charAt(i)-'a';
    //如果 node.son[index]==null,就说明没有这个字符,直接把 s 加进 res 中
    //如果 node.word!=null 就说明这个 s 是含有词根的,直接把词根加进 res 就好了
    if(node.son[index] == null || node.word!=null) break;
    node = node.son[index];
    }
    res.append(node.word!=null ? node.word : s);
    }
    return res.toString();
    }
    }
    class TrieNode{
    TrieNode[] son;
    //使用字符串来标记结束
    String word;
    public TrieNode(){
    //不对字符串进行初始化,用以判断含有词根的结束
    son = new TrieNode[26];
    }
    }
posted @   心是冰冰的  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示