字典树(Trie树)

简介: 字典树

目录

题目1

代码

题目2

代码

🍔🍔🍔代码分析

🍔Trie树🍔

用处:高效地存储字符串集合的数据结构

概述:就是一个树状结构的存储方式,使用二维数组来存储,其中包含了父结点和子结点,从上向下开始遍历,看是否能够找到对应的结点,从而判断能否找到对应的字符串

存储方法(注意标记结束结点)

image.png图像来源:AcWing 835. Trie字符串统计 - AcWing

下面的结点都是新开辟的结点,u代表字母,来确定结点的具体位置

12.png

不知道为什么,这个题在y总的课里面是基础算法,但是在洛谷上却是普及+的

那么下面就先给出两道简单的(可以作为模板使用)

13.1.png 

回归正题

题目1

[NOI2000]单词查找树 (nowcoder.com)

13.2.png

13.3.png

代码

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int son[N][26],cnt[N],idx;
void insert(string s)
{
    int p=0;
    for(int i=0;i<s.size();i++)
    {
        int u=s[i]-'A';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cnt[p]++;
}
int main()
{
    string s;
    while(cin>>s)
    {
        insert(s);
    }
    cout<<idx+1<<endl;
    return 0;
}

while(cin>>s)

边输入边循环,直到输入到结束符EOF为止

题目2

835. Trie字符串统计 - AcWing题库

13.4.png

代码

#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx;
char str[N];
void insert(char *str)
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}
int query(char *str)//str[]
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}
int main()
{
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        char op[2];
        scanf("%s%s", op, str);
        if (*op == 'I') insert(str);//op[0]
        else printf("%d\n", query(str));
    }
    return 0;
}

🍔🍔🍔代码分析

⭐代码里面的int son[N][26],不能写成int  son[N][N],

因为N就很大了,如果写成son[N][N],相当于存储的是N * N,会爆int

⭐int son[N][26];

son[][]存储子节点的位置,因为有26个字母,所以分支最多26条

⭐ int u = str[i] - 'a';

用来记录每个字母的位置是什么

⭐insert()

    if (!son[p][u]) son[p][u] = ++ idx;    p = son[p][u];

如果不存在这个结点不存在它的儿子的话,就创建一个结点,它的值为下一个结点的位置上的值

否则  使 p 指针指向下一个位置

相当于:有路的话,就走下去(idx++),否则建一条路也要走下去(p)

    query()

    if (!son[p][u]) return 0;   p = son[p][u];

如果不存在这个结点的话,就是没有查询到,就要返回0(return 0)

否则  使 p 指针指向下一个位置

⭐cnt[]存储以某节点结尾的字符串个数(同时也起标记作用)

cnt[p]++:表示以这个结点结尾的字符串的个数+1

return cnt[p]; 返回字符串出现的次数

⭐++idx

当前插入的结点是哪一个,加入新的结点就用++idx分配出一个下标

Code over!

相关文章
|
9月前
|
安全 Go 开发者
你真的懂 close(chan) 吗?90% 的 Go 开发者都掉过这个坑!
在 Go 并发编程中,初始化 channel 后直接 `close` 是合法且常见做法,用于广播通知、表示任务完成或作为退出信号。相比发送数据,关闭通道能非阻塞地通知多个 goroutine,更安全高效。理解这一机制有助于构建稳定、优雅的并发系统。
281 0
|
搜索推荐 应用服务中间件 PHP
301重定向完整指南: 原理、应用与实现方法
301重定向是一种永久性URL转发技术,用于将旧链接的权重传递给新URL,有助于SEO优化、提升用户体验和维护网站流量。本文介绍了301重定向的应用场景(如更换域名、HTTP转HTTPS等)、实现方法(Apache、Nginx、PHP等)及最佳实践,并解答了常见问题,帮助用户正确配置以确保网站无缝过渡。建议在操作前备份配置并使用工具验证效果。
1145 10
|
SQL 存储 数据库
《深度剖析SQL数据类型转换:隐式与显式的奥秘》
在SQL中,数据类型转换是基础且关键的操作,分为隐式和显式转换。隐式转换由系统自动完成,虽便捷但可能带来性能损耗、索引失效及数据准确性风险;显式转换通过函数(如CAST、CONVERT)手动实现,更精确可控,能提升性能、增强代码可读性和保障数据准确性。掌握两者特点与应用场景,合理选择转换方式,对编写高效稳定的SQL代码至关重要。同时,注意数据兼容性与错误处理,确保转换操作顺利进行,避免潜在问题。
368 5
|
安全 API
通义千问API获取方法
访问阿里云DashScope官网以获取API-KEY。首先需开通DashScope服务:登录控制台,点击“去开通”,阅读协议后点击“立即开通”。接着获取API-KEY:进入API-KEY管理页面,点击“创建新的API-KEY”,复制并安全保存生成的API-KEY。完成这些步骤后,即可使用API-KEY调用DashScope API。更多详情见[官方文档](https://help.aliyun.com/zh/dashscope/developer-reference/acquisition-and-configuration-of-api-key)。
|
存储 Java 测试技术
ClickHouse Keeper: 一个用 C++ 编写的 ZooKeeper 替代品
ClickHouse Keeper: 一个用 C++ 编写的 ZooKeeper 替代品介绍
71667 34
ClickHouse Keeper: 一个用 C++ 编写的 ZooKeeper 替代品
|
机器学习/深度学习 算法 TensorFlow
深入探索强化学习与深度学习的融合:使用TensorFlow框架实现深度Q网络算法及高效调试技巧
【8月更文挑战第31天】强化学习是机器学习的重要分支,尤其在深度学习的推动下,能够解决更为复杂的问题。深度Q网络(DQN)结合了深度学习与强化学习的优势,通过神经网络逼近动作价值函数,在多种任务中表现出色。本文探讨了使用TensorFlow实现DQN算法的方法及其调试技巧。DQN通过神经网络学习不同状态下采取动作的预期回报Q(s,a),处理高维状态空间。
352 1
|
数据采集 Java API
java怎么设置代理ip:简单步骤,实现高效网络请求
本文介绍了在Java中设置代理IP的方法,包括使用系统属性设置HTTP和HTTPS代理、在URL连接中设置代理、设置身份验证代理,以及使用第三方库如Apache HttpClient进行更复杂的代理配置。这些方法有助于提高网络请求的安全性和灵活性。
866 0
|
监控 Kubernetes Linux
在Linux中,如何排查性能下降问题?
在Linux中,如何排查性能下降问题?
【1】ElementUI 组件实际应用===》按钮的使用
这篇文章详细介绍了Element UI库中的按钮组件的使用方法,包括基础用法、禁用状态、文字按钮、图标按钮、按钮组、加载中状态、不同尺寸的按钮以及按钮的属性说明。文章通过实例代码展示了如何定义按钮样式、添加图标、设置按钮尺寸和类型,并解释了如何绑定方法到按钮以执行操作。
|
Java 开发者 Spring
Spring Boot大法好:解耦、隔离、异步,让代码‘活’起来,性能飙升的秘密武器!
【8月更文挑战第29天】解耦、隔离与异步是Spring Boot中的关键设计原则,能大幅提升软件的可维护性、扩展性和性能。本文通过示例代码详细探讨了这些原则的应用:依赖注入和面向接口编程实现解耦;模块化设计与配置文件实现隔离;`@Async`注解和`CompletableFuture`实现异步处理。综合运用这些原则,可以显著提升软件质量和性能,使系统更加健壮、灵活和高效。
320 0