Python算法题集_实现 Trie [前缀树]

 Python算法题集_实现 Trie [前缀树]

  • 题208:实现 Trie (前缀树)
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【定义数据类+默认字典】
    • 2) 改进版一【初始化字典+无额外类】
    • 3) 改进版二【字典保存结尾信息+无额外类】
  • 4. 最优算法
  • 5. 相关资源

本文为Python算法题集之一的代码示例

题208:实现 Trie (前缀树)

1. 示例说明

  • Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

    请你实现 Trie 类:

    • Trie() 初始化前缀树对象。
    • void insert(String word) 向前缀树中插入字符串 word
    • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false
    • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false

    示例:

    输入
    ["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
    [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
    输出
    [null, null, true, false, true, null, true]解释
    Trie trie = new Trie();
    trie.insert("apple");
    trie.search("apple");   // 返回 True
    trie.search("app");     // 返回 False
    trie.startsWith("app"); // 返回 True
    trie.insert("app");
    trie.search("app");     // 返回 True
    

    提示:

    • 1 <= word.length, prefix.length <= 2000
    • wordprefix 仅由小写英文字母组成
    • insertsearchstartsWith 调用次数 总计 不超过 3 * 104

2. 题目解析

- 题意分解

  1. 本题是为自动补完、拼写检查等创造一个高效率的检索类
  2. 基本的设计思路迭代单词,每层用字典保存,同时还需要保存单词结尾信息【search检测结尾、startWith不检测】

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 可以尝试使用默认字典defaultdict

    2. 本题都是小写字母,因此26个元素的字典就可以保存一个层级

    3. 所有单词字符都是ASCII码,Ord值都在0-127,因此128个元素的字典可以正常使用【超时测试用例,需要128一层】

    4. 可以考虑将单词结尾信息保存在字典中,用一个单词中不会出现的字符即可,比如’#’


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大【可把页面视为功能测试】,因此需要本地化测试解决数据波动问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题本地化超时测试用例自己生成,详见章节【最优算法】,需要安装和部署**NLTK**

3. 代码展开

1) 标准求解【定义数据类+默认字典】

使用默认字典,定位专门的数据类,使用类属性保存单词结尾信息

页面功能测试,马马虎虎,超过33%在这里插入图片描述

import CheckFuncPerf as cfpclass prenode:def __init__(self):self.chars = defaultdict(int)class Trie_base:def __init__(self):self.node = prenode()self.bEnd = Falsedef searchPrefix(self, prefix):tmpNode = selffor achar in prefix:ichar = ord(achar) - ord("a")if tmpNode.node.chars[ichar] == 0:return NonetmpNode = tmpNode.node.chars[ichar]return tmpNodedef insert(self, word):tmpNode = selffor achar in word:ichar = ord(achar) - ord("a")if tmpNode.node.chars[ichar] == 0:tmpNode.node.chars[ichar] = Trie_base()tmpNode = tmpNode.node.chars[ichar]tmpNode.bEnd = Truedef search(self, word):node = self.searchPrefix(word)return node is not None and node.bEnddef startsWith(self, prefix):return self.searchPrefix(prefix) is not NonetmpTrie = Trie_base()
result = cfp.getTimeMemoryStr(testTrie, tmpTrie, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 testTrie 的运行时间为 7127.62 ms;内存使用量为 373008.00 KB 执行结果 = 99

2) 改进版一【初始化字典+无额外类】

将字典数据和单词结尾信息都保存在节点类中,创建类同时初始化字典的128个元素【按题意只需26,本类已经按超时测试改写】

页面功能测试,马马虎虎,超过65%在这里插入图片描述

import CheckFuncPerf as cfpclass Trie_ext1:def __init__(self):self.data = [None] * 128self.bEnd = Falsedef searchPrefix(self, prefix):tmpnode = selffor achar in prefix:ichar = ord(achar)if not tmpnode.data[ichar]:return Nonetmpnode = tmpnode.data[ichar]return tmpnodedef insert(self, word):tmpnode = selffor achar in word:ichar = ord(achar)if not tmpnode.data[ichar]:tmpnode.data[ichar] = Trie_ext1()tmpnode = tmpnode.data[ichar]tmpnode.bEnd = Truedef search(self, word):tmpnode = self.searchPrefix(word)return tmpnode is not None and tmpnode.bEnddef startsWith(self, prefix):return self.searchPrefix(prefix) is not NonetmpTrie = Trie_ext1()
result = cfp.getTimeMemoryStr(testTrie, tmpTrie, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 testTrie 的运行时间为 5857.32 ms;内存使用量为 793700.00 KB 执行结果 = 99

3) 改进版二【字典保存结尾信息+无额外类】

在字典中保存单词结尾信息,将字典数据保存在节点类中,创建类时不初始化字典

页面功能测试,性能卓越,超越96%在这里插入图片描述

import CheckFuncPerf as cfpclass Trie_ext2:def __init__(self):self.tree = {}def insert(self, word):tree = self.treefor achar in word:if achar not in tree:tree[achar] = {}tree = tree[achar]tree["#"] = "#"def search(self, word):tree = self.treefor achar in word:if achar not in tree:return Falsetree = tree[achar]return "#" in treedef startsWith(self, prefix):tree = self.treefor achar in prefix:if achar not in tree:return Falsetree = tree[achar]return TruetmpTrie = Trie_ext2()
result = cfp.getTimeMemoryStr(testTrie, tmpTrie, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 testTrie 的运行时间为 1670.38 ms;内存使用量为 146692.00 KB 执行结果 = 99

4. 最优算法

根据本地日志分析,最优算法为第3种方式【字典保存结尾信息+无额外类】Trie_ext2

本题大概有以下结论:

  1. 独立的变量,如果能保存在字典结构里,减少独立的变量数,可以提升性能
  2. 数据集的默认初始化可能会扩大内存使用,同时数据量过大、内存过大也拖累性能
import random
from nltk.corpus import words
word_list = list(words.words())
def testTrie(aTrie, actions):for act in actions:if act[0]==1:   # insertaTrie.insert(act[1])elif act[0]==2: # searchaTrie.search(act[1])elif act[0]==3: # startsWithaTrie.startsWith(act[1])return 99
import random
actions = []
iLen = 1000000
for iIdx in range(iLen):actions.append([random.randint(1, 3), random.choice(word_list)])
tmpTrie = Trie_base()
result = cfp.getTimeMemoryStr(testTrie, tmpTrie, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))
tmpTrie = Trie_ext1()
result = cfp.getTimeMemoryStr(testTrie, tmpTrie, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))
tmpTrie = Trie_ext2()
result = cfp.getTimeMemoryStr(testTrie, tmpTrie, actions)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 算法本地速度实测比较
函数 testTrie 的运行时间为 7127.62 ms;内存使用量为 373008.00 KB 执行结果 = 99
函数 testTrie 的运行时间为 5857.32 ms;内存使用量为 793700.00 KB 执行结果 = 99
函数 testTrie 的运行时间为 1670.38 ms;内存使用量为 146692.00 KB 执行结果 = 99

5. 相关资源

本文代码已上传到CSDN,地址:**Python算法题源代码_LeetCode(力扣)_**实现Trie(前缀树)

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

自定义神经网络三之梯度和损失函数激活函数

文章目录 前言梯度概述梯度下降算法梯度下降的过程 optimize优化器 梯度问题梯度消失梯度爆炸 损失函数常用的损失函数损失函数使用原则 激活函数激活函数和损失函数的区别激活函数Relu-隐藏层激活函数Sigmoid和Tanh-隐藏层Sigmoid函数Tanh&#xff08;双曲正切&#xff09; &l…

Panalog大数据日志审计系统libres_syn_delete.php命令执行漏洞

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 1、产品简介 Panalog大数据日志审计系统定位于将大数据产品应用于高校…

Linux之vim的使用详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.vim简介 二.vim的基本概念 三.vim的基本操作 3.1准备 …

STL - B树

1、常见的搜索结构 种类数据格式时间复杂度顺序查找无要求O(N&#xff09;二分查找有序O( )二叉搜索树无要求O(N)二叉平衡树(AVL树和红黑树)无要求O( )哈希无要求O(1) 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景…

图像的压缩感知的MATLAB实现(第3种方案)

前面介绍了两种不同的压缩感知实现&#xff1a; 图像压缩感知的MATLAB实现&#xff08;OMP&#xff09; 压缩感知的图像仿真&#xff08;MATLAB源代码&#xff09; 上述两种方法还存在着“速度慢、精度低”等不足。 本篇介绍一种新的方法。 压缩感知&#xff08;Compressed S…

macOS系统下载IDEA的操作流程

第一步 进入官网 Download IntelliJ IDEA – The Leading Java and Kotlin IDE 第二步 根据mac的芯片选择版本下载 芯片的查看位置是【设置】-【通用】-【关于本机】-第二个&#xff0c;我的是Apple芯片&#xff0c;选Apple Silicon -- 第三步 右上角下载处打开安装包&…

汇编语言与接口技术实践——秒表

1. 设计要求 基于 51 开发板,利用键盘作为按键输入,将数码管作为显示输出,实现电子秒表。 功能要求: (1)计时精度达到百分之一秒; (2)能按键记录下5次时间并通过按键回看 (3)设置时间,实现倒计时,时间到,数码管闪烁 10 次,并激发蜂鸣器,可通过按键解除。 2. 设计思…

第十三章 Linux——备份与恢复

第十三章 Linux——备份与恢复 基本介绍安装dump和restore使用dump完成备份dump语法说明dump应用案例1dump应用案例2dump-w查看备份时间文件备份文件或者目录备注 使用restore基本语法基本介绍restore基本语法应用案例1应用案例2应用案例3应用案例4 基本介绍 实体机无法做快照…

SpringBoot:数据访问-整合 spring-boot-starter-data-jpa

点击查看数据访问demo&#xff1a;LearnSpringBoot06DataJPA Spring Data JPA - Reference 文档 简介 Spring Data的JPA模块包含一个允许定义存储库bean的自定义名称空间。它还包含JPA特有的某些特性和元素属性。通常&#xff0c;可以使用repositories元素来设置JPA存储库: 点…

学习使用在mysql中查询指定字段字符串包含多个字符串的方法

学习使用在mysql中查询指定字段字符串包含多个字符串的方法 使用LIKE关键字使用REGEXP关键字使用FIND_IN_SET函数使用INSTR函数和AND关键字 使用LIKE关键字 SELECT * FROM table_name WHERE column_name LIKE %string1% AND column_name LIKE %string2%;使用LIKE关键字&#x…

异常统一处理:Exception(兜底异常)

一、引言 本篇内容是“异常统一处理”系列文章的重要组成部分&#xff0c;主要聚焦于对 Exception&#xff08;兜底异常&#xff09; 的原理解析与异常处理机制&#xff0c;并给出测试案例。 关于 全局异常统一处理 的原理和完整实现逻辑&#xff0c;请参考文章&#xff1a; 《…

yolov8学习笔记(二)模型训练

目录 yolov8的模型训练 1、制作数据集&#xff08;标记数据集&#xff09; 2、模型训练&#xff08;标记数据集、参数设置、跟踪模型随时间的性能变化&#xff09; 2.1、租服务器训练 2.2、加训练参数 2.3、看训练时的参数&#xff08;有条件&#xff0c;就使用TensorBoard&…

《最新出炉》系列初窥篇-Python+Playwright自动化测试-27-处理单选和多选按钮-番外篇

1.简介 前边几篇文章是宏哥自己在本地弄了一个单选和多选的demo&#xff0c;然后又找了网上相关联的例子给小伙伴或童鞋们演示了一下如何使用playwright来处理单选按钮和多选按钮进行自动化测试&#xff0c;想必大家都已经掌握的八九不离十了吧。这一篇其实也很简单&#xff1a…

JavaSE——面向对象基础(4/4)-成员变量和局部变量的区别、面向对象综合案例(电影信息系统)

目录 补充&#xff1a;成员变量和局部变量的区别 面向对象综合案例 设计一个电影类 IDEA快捷操作 设计一个电影操作类 准备电影数据 业务处理 运行结果 补充&#xff1a;成员变量和局部变量的区别 区别成员变量&#xff08;对象的属性&#xff09;局部变量类中位置不同…

Project_Euler-07 题解

Project_Euler-07 题解 题目 思路 一个线性筛解决问题&#xff0c;当然也可以用埃式筛或者标准的暴力破解&#xff0c;这里选用最优秀的方式&#xff0c;顺便复习一下线性筛的内容&#xff1a; #include<stdio.h> #include<stdlib.h> #include<math.h> #in…

spring源码概念解析-spring生命周期

1.Spring生命周期 BeanFactory的⽣命周期 ApplicationContext的⽣命周期 初始化的过程都是⽐较⻓&#xff0c;我们可以分类来对其进⾏解析&#xff1a; Bean⾃身的⽅法&#xff1a;如调⽤ Bean 构造函数实例化 Bean&#xff0c;调⽤ Setter 设置 Bean 的属性值以及通 过的 in…

matlab新能源汽车三自由度操纵稳定性分析及优化

1、内容简介 略 可以交流、咨询、答疑 55-新能源汽车三自由度操纵稳定性分析及优化 2、内容说明 略 摘 要 电动化是节能减排、寻求替代能源的最佳途径&#xff0c;已成为行业共识&#xff0c;论文基于江西科技学院桑塔纳轿车油改气项目&#xff0c;在拆除发动机、变速…

Unity(第六部)向量的理解和算法

标量:只有大小的量。185 888 999 &#xff08;类似坐标&#xff09; 向量:既有大小&#xff0c;也有方向。&#xff08;类似以个体为主体的方向&#xff0c;前方一百米&#xff09; 向量的模:向量的大小。&#xff08;类似以个体为主体的方向&#xff0c;前方一百米、只取一百米…

【Crypto | CTF】BugKu 简单的RSA

天命&#xff1a;这题也不算简单了&#xff0c;要反编译&#xff0c;要灵活一点 首先收到pyc文件&#xff0c;拿去反编译出来&#xff0c;可以用在线反编译&#xff0c;也可以用工具反编译 在线&#xff1a;python反编译 - 在线工具 工具&#xff1a;https://download.csdn.n…

基于Java的传统工艺品销售系统的设计与实现

网上购物尚未流行前需要购买传统工艺品的人们都是到遍布于大街小巷的商场商店中进行挑选购买&#xff0c;除非抱有非常明确的目标&#xff0c;否则是很难在短时间内挑选购买到所需传统工艺品的。网上购物在国内的兴起则彻底颠覆了传统的线下购物模式&#xff0c;线下实体商场也…