Trie树

Trie(字典树)是一种用于实现字符串检索的多叉树。

Trie的每一个节点都可以通过 c 转移到下一层的一个节点。

我们可以看作可以通过某个字符转移到下一个字符串状态,直到转移到最终态为止。这是后话……

我们以插入了字符串 abaab 三个字符串的Trie树为例:

其实一看图就非常清晰了

在上图中,如果我们需要继续插入一个字符串 abc,那么就只需要新建一个节点即可

思路清晰,那么代码如何实现?

  • 首先是插入部分:
struct Node {
int kids[65];
int cnt;
} nodes[N]; #define kids(p, j) nodes[p].kids[j]
#define cnt(p) nodes[p].cnt void insert(char * s, int len) {
int p = 0;
for (int i = 0; i < len; ++i) {
int j = discrete(s[i]);
if (!kids(p, j)) kids(p, j) = ++usage; // 新建节点
p = kids(p, j);
}
    ++cnt(p);
}

discrete指的是离散化,例如这里是将 a-z0-25 表示

最终的 cnt 表示有几个字符串在当前节点结束。

  • 然后是查询部分

我们还是利用类似的思路,一个一个向下走。

例如我们要查询字符串 aba,那么我们从根节点 0 开始,通过 a 走到 1 节点,通过 b 走到 4 节点,发现没有 a 的子节点,表明没有这个字串,结束寻找。

// 这里是查询这个字符串出现了多少次,为0就是没有出现
int count(char * s, int len) {
int p = 0;
for (int i = 0; i < len; ++i) {
int j = discrete(s[i]);
if (!kids(p, j)) return 0;
p = kids(p, j);
}
return cnt(p);
}

其实主要操作就这两个,我们考虑一下空间和时间复杂度:

时间复杂度很明显是与字符串长度相关的,我们每处理一个字符走一个节点,也就是 \(O(L)\) 的复杂度,那么总的复杂度就是 \(O(NL)\)

至于空间复杂度,每处理一个字符串至多新建 \(L\) 个节点,那么就是 \(O(L)\) ,每一个节点的大小关乎字符串的字符集大小,所以我们认为是 \(O(C)\) 那么总共就是 \(O(NLC)\) ,但是,在实际中,远远达不到此复杂度(除非毒瘤出题人想卡你),例如最初的图,一共 4 个字符串,但是只有 5 个节点……

例题

【模板】字典树 - 洛谷

注意题意,以询问所给作为前缀,求有多少个字符串满足此前缀

那么我们需要魔改一下 insert 函数即可……将 ++cnt(p) 放入循环中即可

还请读者仔细思考

[USACO12DEC]First! G - 洛谷

这道题非常的神奇……考虑先建Trie树,如果某一个字符串的字典序比其他任何字符串都大,那么一定不存在为其前缀的字符串。

再考虑字典序,如果使 s 其字典序最大,那么每一个分叉点上,s[i] 比其他所有存在的分叉都要大。

如样例:omm, moo, mom

如果要使 omm 最大那么在第一层上满足 o > m,其他层上没有分叉。

如果要使 moo 最大,那么第一层上满足 m > o,第三层上满足 o > m,条件相悖,所以不可行。

其他同理。

那么我们如何判断条件相悖?可以借鉴 2-SAT 的思路,通过大于关系建图,如果存在环,那么不可行。

判环用拓扑,谁用Tarjan啊

最终,每一个串判断一遍即可。

[BJOI2016]IP地址 - 洛谷

这道题就是Trie的一种特殊用法。

有点类似线段树的区间标记。

我们考虑改变一个规则对其整个子树都有影响,那么我们考虑什么时候影响抵消?更深的点会阻挡了标记的下传。那么我们记录一下各个点的标记情况,通过类似线段树的方法下传标记即可。

正确性显然。

扩展

Trie树实际上是 AC自动机 和 回文自动机 等自动机的载体,需要经过一点点小变换。

在此不展开叙述,详见我的其他文章。

算法学习笔记(15): Trie(字典树)的更多相关文章

  1. 道长的算法笔记:Trie字典树

    Trie模板 Trie 是一种用于实现字典序快速检索的多叉树结构,Trie 每个节点都有若干的字符指针,若在扫扫描字符串时扫到字符 \(c\),则沿着当前节点 \(c\) 字符指针走向该指针指向的节点 ...

  2. 算法学习笔记(20): AC自动机

    AC自动机 前置知识: 字典树:可以参考我的另一篇文章 算法学习笔记(15): Trie(字典树) KMP:可以参考 KMP - Ricky2007,但是不理解KMP算法并不会对这个算法的理解产生影响 ...

  3. 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  4. 算法导论:Trie字典树

    1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...

  5. 标准Trie字典树学习二:Java实现方式之一

    特别声明: 博文主要是学习过程中的知识整理,以便之后的查阅回顾.部分内容来源于网络(如有摘录未标注请指出).内容如有差错,也欢迎指正! 系列文章: 1. 标准Trie字典树学习一:原理解析 2.标准T ...

  6. SQL反模式学习笔记3 单纯的树

    2014-10-11 在树形结构中,实例被称为节点.每个节点都有多个子节点与一个父节点. 最上层的节点叫做根(root)节点,它没有父节点. 最底层的没有子节点的节点叫做叶(leaf). 中间的节点简 ...

  7. SQL反模式学习笔记15 分组

    目标:查询得到每组的max(或者min等其他聚合函数)值,并且得到这个行的其他字段 反模式:引用非分组列 单值规则:跟在Select之后的选择列表中的每一列,对于每个分组来说都必须返回且仅返回一直值. ...

  8. C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  9. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  10. 算法学习笔记(5): 最近公共祖先(LCA)

    最近公共祖先(LCA) 目录 最近公共祖先(LCA) 定义 求法 方法一:树上倍增 朴素算法 复杂度分析 方法二:dfs序与ST表 初始化与查询 复杂度分析 方法三:树链剖分 DFS序 性质 重链 重 ...

随机推荐

  1. 他来了他来了,.net开源智能家居之苹果HomeKit的c#原生sdk【Homekit.Net】1.0.0发布,快来打造你的私人智能家居吧

    背景介绍 hi 大家好,我是三合,作为一个非著名懒人,每天上完班回到家,瘫在沙发上一动都不想动,去开个灯我都嫌累,此时,智能家居拯救了我,只需要在手机点点点,开关灯,空调,窗帘就都搞定了,一开始我用的 ...

  2. Mac搭建appium环境及python运行代码示例

    Appium主要是通过调用安卓提供的接口来执行命令的,所以需要安装Java和安卓SDK. 1.安装Appium服务端 appium的服务端是基于node的,直接使用npm(node包管理器)安装即可, ...

  3. Alibaba/IOC-golang 正式开源 ——打造服务于go开发者的IOC框架

    简介: IOC(inversion of control)即控制反转,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.IOC-golang 是一款服务于Go语言开发者的依赖注入框架 ...

  4. 21.3K star!推荐一款可视化自动化测试/爬虫/数据采集神器!功能免费且强大!

    大家好,我是狂师! 在大数据时代,信息的获取与分析变得尤为重要.对于开发者.数据分析师乃至非技术人员来说,能够高效地采集网络数据并进行分析是一个强有力的工具.今天,我要向大家推荐的是一款功能强大.操作 ...

  5. dotnet 8 WPF 支持在 RDP 远程桌面状态下启用渲染硬件加速

    本文将和大家介绍在 dotnet 8 里 WPF 引入的新功能之一,在 RDP 远程桌面状态下启用渲染硬件加速 在 dotnet 8 之前,在用户进行 RDP 远程桌面时 WPF 应用将默认关闭硬件渲 ...

  6. WPF 性能测试

    本文收藏我给 WPF 做的性能测试.在你开始认为 WPF 的性能存在问题的时候,不妨来这篇博客里找找看我做过的测试.我记录的测试都是比较纯净的测试项目,没有业务逻辑的干扰,写法也正常,可以更加真实反映 ...

  7. Unity3D OpenVR 虚拟现实 保龄球打砖块游戏开发

    据说水哥买了 Valve Index 设备,既然这个设备这么贵,不开发点有(zhi)趣(zhang)游戏就感觉对不起这个设备.本文将来开始着手开发一个可玩性不大,观赏性极强的保龄球打砖块游戏.这仅仅只 ...

  8. 如何参与 .NET 的开发和设计

    现在 dotnet 属于 dotnet 基金会,所有开发者都可以向 dotnet 贡献代码和参与 .NET 的设计,参与路线决策.本文来告诉大家一些基本玩法,带着小伙伴们入坑 注意哦,参与 dotne ...

  9. linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)

    一.JNI技术 JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植. SUN公司发布的Java 本地接口(JNI)提供了将 ...

  10. MDK在头文件中使用预编译器时,#ifdef 无效的问题

    问题:在头文件中使用预编译时,会出现无效的现象 在a.h文件中定义了宏AA_TEST,如下所示 #ifndef __A_H #define __A_H #define AA_TEST #endif 在 ...