Trie字符串统计-java

Trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。

目录

前言☀

一、Trie字符串统计☀

二、算法思路☀

1.Trie树定义🌙

2.变量解释🌙

3.插入操作🌙

4.Trie树查找操作 🌙

三、代码如下☀

1.代码如下:🌙

2.读入数据🌙

3.代码运行结果🌙

 4.运行结果解释🌙

总结☀


前言☀

Trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Trie字符串统计☀

维护一个字符串集合,支持两种操作:

  1. I x 向集合中插入一个字符串 x;
  2. Q x 询问一个字符串在集合中出现了多少次。

共有 N 个操作,所有输入的字符串总长度不超过 100000,字符串仅包含小写英文字母。

输入格式

第一行包含整数 N,表示操作数。

接下来 N行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。

输出格式

对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。

每个结果占一行。

数据范围

1≤N≤2∗10000

二、算法思路☀

1.Trie树定义🌙

图1.1Trie树示例 

 Trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。

Trie树是用来高效的存储和查找字符串的集合的数据结构。

基本性质:

1、根节点不包含字符,除根节点意外每个节点只包含一个字符。

2、从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。

3、每个节点的所有子节点包含的字符串不相同。

图1.1中我们用trie树存储了abcdef、abdef、aced、bcdf、bcff、cdaa、bcdc字符串。

我们会在一个单词的结尾来做一个标记,来表示到这里有一个完整的单词。

2.变量解释🌙

我们引入整型变量N为100010,用来表示树深最高100000个结;然后有因为字符串中只有小写字母,那么一个结点最多有26个分支,那么我们用一个二维整型数组son来存储,共有N行26列;用一维整型数组cnt来存储以某节点结束的字符串的个数,同时起到字符串结束的作用,引入一个整型变量index,初始化为0,用来表示空节点。

3.插入操作🌙

插入操作我们按照一个字符串的字母顺序第一个字符是根节点的分支,然后下一个字母是上一个字母的分支,直到单词的结束;遇到相同前缀的单词在相同单词的前缀后的不同分支接着串连字母,当然每个单词的最后一个字母都会有一个结束标志。具体模拟过程可以看图1.1.

图3.1模拟过程

对于一个字符串str,获取对应的字符数组arr,建立一个整型变量p初始化为0,相当于一个指针变量指向当前节点,我们遍历每个字符arr[i] ,然后用u = arr[i] - 'a',将每个字符转换成数字关系,当该字符未被放入Trie树中时即(son[p][u] == 0),将son[p][u] = ++index;意思是当该节点不存在的时候,我们创建出来,然后数组中的值是下一个节点的位置;然后将当前节点的指针p指向下一个节点的位置即 p = son[p][u];当该字符串的所有字符遍历结束后,将cnt[p]++;此时p的值就是当前节点的位置,还因为index的值是随着我们没新创建一个节点增加的,是唯一的,它可以用来表示字符串结束的标识。

    public static void insert(String str){char[] arr = str.toCharArray();int p = 0;for(int i = 0;i < arr.length;i++){int u = arr[i] - 'a';//字符不在Trie树中if(son[p][u] == 0){//创建一个节点,数组中的值为下一个节点的位置son[p][u] = ++index;}//使指针指向下一个节点的位置p = son[p][u];}//结束时标记,记录以此节点为结尾的字符串的个数cnt[p]++;}

4.Trie树查找操作 🌙

我们还用图1.1来看,当我们查找字符串acf的时候。从root-> a -> c - > e,此时a的后面没有f,就说明Trie树中不存在acf字符串;当我们字符串cda的时候,从root - > c - > d - > a,但是字符a没有单词结束标志,那么说明Trie树中同样也没有字符串cda。

我们传入一个字符串str,然后利用对应的字符数组arr,建立一个整型变量p初始化为0,相当于一个指针变量指向当前节点,我们遍历每个字符arr[i] ,然后用u = arr[i] - 'a',将每个字符转换成数字关系,当我们发现该字符不在Trie树中时即son[p][u] == 0,即该字符串不存在直接返回0即可;当该字符存在,那么就将p指针指向该节点的下一个节点位置 p = son[p][u],将该字符数组遍历完毕后,最后返回该字符串的个数就是以最后一个节点的位置对应的cnt数组中的值即cnt[p]。

    public static int query(String str){char[] arr = str.toCharArray();int p = 0;for(int i = 0;i < arr.length;i++){int u = arr[i] - 'a';//不存在if(son[p][u] == 0){return 0;}p = son[p][u];}//返回字符串出现的次数return cnt[p];}

三、代码如下☀

1.代码如下:🌙


import java.io.*;
import java.util.*;public class Trie字符串统计 {static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//一个字符串最多100000个字符static int N = 100010;//存储子节点后面的分支,因为只有小写字母,故只有26个分支static int[][] son = new int[N][26];//存储以某节点结束的字符串的个数,同时起到字符串结束的标志作用static int[] cnt = new int[N];//下标是0的点既是根节点static int index = 0;public static void main(String[] args) throws Exception {Scanner sc = new Scanner(br);int m = sc.nextInt();while (m-- > 0){String cmd = sc.next();String str = sc.next();if (cmd.equals("I")){insert(str);}else if (cmd.equals("Q")){pw.println(query(str));}}pw.flush();}public static void insert(String str){char[] arr = str.toCharArray();int p = 0;for(int i = 0;i < arr.length;i++){int u = arr[i] - 'a';//字符不在Trie树中if(son[p][u] == 0){//创建一个节点,数组中的值为下一个节点的位置son[p][u] = ++index;}//使指针指向下一个节点的位置p = son[p][u];}//结束时标记,记录以此节点为结尾的字符串的个数cnt[p]++;}public static int query(String str){char[] arr = str.toCharArray();int p = 0;for(int i = 0;i < arr.length;i++){int u = arr[i] - 'a';//不存在if(son[p][u] == 0){return 0;}p = son[p][u];}//返回字符串出现的次数return cnt[p];}
}

2.读入数据🌙

5
I abc
Q abc
Q ab
I ab
Q ab

3.代码运行结果🌙

1
0
1

 4.运行结果解释🌙

图4.1 

插入abc后查询abc为1;查询ab不存在为0; 插入ab;查询ab存在为1。


总结☀

主要了解Trie树的构造性质后,直到如何插入字符串,如何查询字符串;了解代码中各个变量的含义,直到每一步是干什么,可以跟着图示自己手动模拟一下,体验一下过程,加深自己的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/18537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【class18】人工智能初步----语音识别(4)

【class17】 上节课&#xff0c;我们学习了: 语音端点检测的相关概念&#xff0c;并通过代码切分和保存了音频。 本节课&#xff0c;我们将学习这些知识点&#xff1a;1. 序列到序列模型2. 循环神经网络3. 调用短语音识别接口 知其然&#xff0c;知其所以然 在调用语…

数组单调栈-901. 股票价格跨度、leetcode

单调栈作为一种数据结构在求解类递增、递减方面的题目中有较为广泛的应用&#xff0c;在以往的leetcode中所见到的相关单调栈的题目均为单一元素&#xff0c;今天刷到901题目时&#xff0c;想到了将数组元素作为单调栈中元素的方法进行求解。 题目链接及描述 901. 股票价格跨…

【c++leetcode】69. Sqrt(x)

问题入口 二分搜索 最困难的是能否意识到用二分搜索法解题。 算术平方根的区间在[1, x] 。代码如下&#xff1a; class Solution { public:int mySqrt(int x) {if (x 1 || x 0){return x;}int64_t start 1;int64_t end x;while (start < x){int64_t mid start (en…

以果决其行,只为文化的传承

从他们每一个人的身上&#xff0c;我们看到传神的东西&#xff0c;就是他们都能用结果&#xff0c;去指引自己前进的方向&#xff0c;这正是我要解读倪海厦老师的原因&#xff0c;看倪海厦2012年已经去世&#xff0c;到现在已经十几年时间了&#xff0c;但是我们看现在自学中医…

【Pandas】深入解析`pd.to_sql()`函数

【Pandas】深入解析pd.to_sql()函数 &#x1f308; 欢迎莅临我的个人主页&#x1f448;这里是我深耕Python编程、机器学习和自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;并乐于分享知识与经验的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1…

2024年第六届中青杯数学建模竞赛浅析

获取比赛资料&#xff0c;请关注gzh“小何数模”&#xff01; 本次中青杯数学建模的赛题已正式出炉&#xff0c;无论是赛题难度还是认可度&#xff0c;该比赛都是仅次于数模国赛的独一档&#xff0c;可以用于国赛前的练手训练。考虑到大家解题实属不易&#xff0c;为了帮助大家…

JavaSE:StringBuilder和StringBuffer类

1、引言 在上一篇文章中&#xff0c;我们理解了字符串的常用方法&#xff0c;细心的同学大概已经发现&#xff0c;不管是将字符串中的字符转变为大写或小写&#xff0c;或是完成字符串的替换&#xff0c;又或是去除空白字符等等&#xff0c;只要涉及到字符串的修改&#xff0c…

【PB案例学习笔记】-10 进度条使用

写在前面 这是PB案例学习笔记系列文章的第10篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

Java用反射reflect来实例化对象: class.getDeclaredConstructor().newInstance()

Java用反射reflect来实例化对象: class.getDeclaredConstructor().newInstance() 从java9开始, class.newInstance()已过时, 被加上Deprecated强烈反对注解 SuppressWarnings("removal")CallerSensitiveDeprecated(since"9")public T newInstance()throws …

防止自动化攻击的最佳实践

防止自动化攻击的最佳实践 在当今的网络安全环境中&#xff0c;保护用户账户免受自动化攻击已成为每个网站和应用程序的重要任务。攻击者可以利用多种不同类型的自动化攻击来尝试破坏用户账户。本文将详细介绍常见的攻击类型及其防御机制&#xff0c;帮助您更好地保护用户账户…

adb 连接机顶盒命令

抓机顶盒日志的方法&#xff0c;使用此命令进行抓日志&#xff0c;个别无法抓日志的盒子可以使用此方法 1、安卓9.0版本查询命令 ps -ef |grep com.cm.webos.iptv 2、安卓4.4版本查询命令 ps |grep com.cm.webos.iptv 3、查询顺序&#xff1a;首先进入shell下进行操作 adb she…

C++青少年简明教程:for循环语句

C青少年简明教程&#xff1a;for循环语句 C的for循环语句是一种迭代控制语句&#xff0c;用于重复执行一段代码。 语法格式&#xff1a; for(表达式1&#xff1b;表达式2&#xff1b;表达式3) 循环体 for循环语句执行流程图&#xff1a; 不太好理解&#xff0c;请看下图&am…

VSCode配置Lua5.4安装

参考&#xff1a;VSCode 配置 Lua 开发环境(清晰明了)_lua vscode-CSDN博客 1.下载 Lua Binaries Download (sourceforge.net) 2.配置环境变量 解压放到某文件夹&#xff1a; 环境变量&#xff1a; 3.VSCode安装插件 4.配置 5.测试

Python | Leetcode Python题解之第116题填充每个节点的下一个右侧节点指针

题目&#xff1a; 题解&#xff1a; class Solution:def connect(self, root: Node) -> Node:if not root:return root# 从根节点开始leftmost rootwhile leftmost.left:# 遍历这一层节点组织成的链表&#xff0c;为下一层的节点更新 next 指针head leftmostwhile head:#…

快解析动态域名解析,实现外网访问内网数据库

今天跟大家分享一下如何借助快解析动态域名解析&#xff0c;在两种特定网络环境下&#xff0c;实现外网访问内网mysql数据库。 第1种网络环境&#xff1a;路由器分配的是动态公网IP&#xff0c;且有路由器登录管理权限。如何实现外网访问内网mysql数据库&#xff1f; 针对这种…

继承与Object

一.继承 Java语言的继承&#xff1a;单继承 1.类和类之间的关系 (1)组合关系 公司和员工&#xff0c;学校和学生 (2)继承关系 学生和人 二.Object类 public class Object {private static native void registerNatives();static {registerNatives();} 1.finalize() 对象…

FPGA时钟:驱动数字逻辑的核心

一、引言 在FPGA&#xff08;现场可编程门阵列&#xff09;设计中&#xff0c;时钟信号是不可或缺的关键要素。时钟信号作为时序逻辑的心跳&#xff0c;推动着FPGA内部各个存储单元的数据流转。无论是实现复杂的逻辑运算还是处理高速数据流&#xff0c;都需要精确的时钟信号来保…

Vanna使用ollama分析本地MySQL数据库

上一章节中已经实现了vanna的本地运行&#xff0c;但是大模型和数据库都还是远程的&#xff0c;因为也就没办法去训练&#xff0c;这节一起来实现vanna分析本地mysql数据库&#xff0c;因为要使用本地大模型&#xff0c;所以开始之前需要给本地安装好大模型&#xff0c;我这里用…

WPF/C#:理解与实现WPF中的MVVM模式

MVVM模式的介绍 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种设计模式&#xff0c;特别适用于WPF&#xff08;Windows Presentation Foundation&#xff09;等XAML-based的应用程序开发。MVVM模式主要包含三个部分&#xff1a;Model&#xff08;模型&#xff09;、…

期权具体怎么交易详细的操作流程?

期权就是股票&#xff0c;唯一区别标的物上证指数&#xff0c;会看大盘吧&#xff0c;交易两个方向认购做多&#xff0c;认沽做空&#xff0c;双向t0交易&#xff0c;期权具体交易流程可以理解选择方向多和空&#xff0c;选开仓的合约&#xff0c;买入开仓和平仓没了&#xff0…