Trie树——字典树,单词查找树

问题就是给出n个单词,询问q次,看某单词是否在这些单词中,单词最长为l。如果使用暴力遍历的话,复杂度可达到O(n*q*l),很显然,一般会超时的。因此,我们发现了Trie树复杂度降为O((n+q)*l)。

Trie树是个什么样的数据结构

int son[N][26], cnt[N], idx;
// 0号点既是根节点,又是空节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量

idx:插入顺序标号,全局变量

son[p][x]=i:p表示新插入字母的前一个字母的标号,x表示新字母-'a'的值,i指新插入字母的标号。

cnt[i]:i表示字母标号,cnt[i]表示该字母作为结尾的同一单词出现的个数。

举个例子吧!

依次插入abc,ac,bb

就节点6而言:i=6毋庸置疑,b的前一个单词是b,6的前置节点是5,所以p=5,b-a=1,所以x=1,因此son[5][1]=6。且b是最后一个单词,所以cnt[6]++,cnt[6]=1.

咋写代码

插入新单词

  • 初始位置标在头结点上。
  • 提取第一个字母,看是否在第一层子节点中(?son[0][x]),如果没有,就插入,新节点的标号是++idx;如果有直接下一步。
  • 位置下移到新节点,提取第二个字母,重复上一步操作。
  • 遍历完整个单词以后,最后一个字母cnt++

这里的p很像一个箭头指在当前的节点上,可以把它看做一个指针

// 插入一个字符串
void insert(char str[])
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int x = str[i] - 'a';
        if (!son[p][x]) son[p][x] = ++ idx;
        p = son[p][x];
    }
    cnt[p] ++ ;
}

譬如:在上面的基础上,插入bm

 查询单词出现次数

int find(char str[])
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int x = str[i] - 'a';
        if (!son[p][x]) return 0;
        p = son[p][x];
    }
    return cnt[p];
}

与插入大同小异!由于son[][]是全局变量,初始化都是0,所以当son[p][x]==0时,就说明该字母不在树里,因此就无法查询。

模板题

于是他错误的点名开始了 - 洛谷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值