【问题标题】:What can be a faster implementation of trie for the following use case?对于以下用例,什么可以更快地实现 trie?
【发布时间】:2023-06-26 15:17:01
【问题描述】:

我正在尝试解决problem,本质上我们需要从字典中找到所有按字典顺序具有给定前缀的单词。

我正在使用 Trie 数据结构来完成任务,但我的解决方案只是超时了,有什么更有效/更快的方法来解决这个问题?

我目前的实现是

class trie{
    node root=new node();
    class node{
        node child[]=new node[26];
        boolean is_leaf=false;
    }

    public void add(char c[])
    {
        node root=this.root;
        int pos=0,c1=0;
        while(pos<c.length)
        {
            c1=c[pos]-'a';
            if(root.child[c1]==null)
            {
                root.child[c1]=new node();
            }
            root=root.child[c1];
            pos++;
        }
        root.is_leaf=true;
    }
    public ArrayList<String> search(String s)
    {
        char c[]=s.toCharArray();
        node root=this.root;
        int pos=0,c1=0;
        while(pos<c.length)
        {
            c1=c[pos]-'a';
            if(root.child[c1]==null)
            {
                root.child[c1]=new node();
            }
            root=root.child[c1];
            pos++;
        }
        ArrayList<String> ans=new ArrayList<>();
        build_recursive(root,s,new StringBuilder(),ans);
        return ans;

    }
    public void build_recursive(node root,String prefix,StringBuilder cur, ArrayList<String> ans)
    {
        if(root.is_leaf&&cur.length()!=0)
        {
            String s=prefix+cur.toString();
            ans.add(s);
        }

        for(int i=0;i<26;i++)
        {
            if(root.child[i]!=null)
            {
                char c=(char) (i+'a');
                cur.append(c);
                build_recursive(root.child[i], prefix, cur, ans);
                cur.deleteCharAt(cur.length()-1);

            }
        }
    }

}

函数 Search 返回共享给定前缀的所有单词的排序列表。

还有更好的数据结构我可以使用吗?

【问题讨论】:

  • 提示:对于工作代码,您最好转到 codereview.stackexchangec.om 。你看 - SO 是关于帮助解决特定问题,而不是“请阅读我的代码,编译它,运行它并建议如何改进它”之类的问题。
  • 我投票结束这个问题,因为提问者正在寻找代码改进建议。
  • 旁注:请阅读一些 java 编码风格指南。类以大写字母开头;并且方法名称中没有“_”。
  • @Jägermeister 另一方面,OP 的算法对于 OP 的问题确实不是一个好主意。去*!
  • @tucuxi 因此是“glib”。

标签: java string algorithm data-structures trie


【解决方案1】:

Tries 擅长查找另一个字符串的子字符串。但是,您正在字典中搜索单词 - 子字符串匹配并不是真正需要的。此外,一旦您找到带有前缀的第一个单词,下一个单词(如果存在)将就在它旁边。无需复杂的搜索!

Tries 也因节点构建而产生大量开销,然后需要用指针引用(= 额外空间要求)。指针很慢。在 C++ 中,迭代链表can be 20x slower 比迭代数组,除非所有节点都井井有条。

这个问题很可能可以通过以下方式解决

  • 将所有单词读入字符串的 ArrayList:O(n),其中 n = words
  • 对 ArrayList 进行排序:O(n log n)
  • 对于每个前缀查询,
    • 使用binary search查找前缀的第一个匹配项:O(log n),并且已经在标准库中实现
    • 返回匹配的连续元素,直到匹配耗尽:O(m),m = 匹配数

在理论上的复杂性上,这比 Tries 更快,并且由于内存布局而快得多 - 当你不需要这样做时,弄乱指针是很昂贵的。

【讨论】: