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 cfp

class prenode:
 def __init__(self):
     self.chars = defaultdict(int)

class Trie_base:
 def __init__(self):
     self.node = prenode()
     self.bEnd = False

 def searchPrefix(self, prefix):
     tmpNode = self
     for achar in prefix:
         ichar = ord(achar) - ord("a")
         if tmpNode.node.chars[ichar] == 0:
             return None
         tmpNode = tmpNode.node.chars[ichar]
     return tmpNode

 def insert(self, word):
     tmpNode = self
     for 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 = True

 def search(self, word):
     node = self.searchPrefix(word)
     return node is not None and node.bEnd

 def startsWith(self, prefix):
     return self.searchPrefix(prefix) is not None

tmpTrie = 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 cfp

class Trie_ext1:
 def __init__(self):
     self.data = [None] * 128
     self.bEnd = False

 def searchPrefix(self, prefix):
     tmpnode = self
     for achar in prefix:
         ichar = ord(achar)
         if not tmpnode.data[ichar]:
             return None
         tmpnode = tmpnode.data[ichar]
     return tmpnode

 def insert(self, word):
     tmpnode = self
     for achar in word:
         ichar = ord(achar)
         if not tmpnode.data[ichar]:
             tmpnode.data[ichar] = Trie_ext1()
         tmpnode = tmpnode.data[ichar]
     tmpnode.bEnd = True

 def search(self, word):
     tmpnode = self.searchPrefix(word)
     return tmpnode is not None and tmpnode.bEnd

 def startsWith(self, prefix):
     return self.searchPrefix(prefix) is not None

tmpTrie = 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 cfp

class Trie_ext2:
 def __init__(self):
     self.tree = {}

 def insert(self, word):
     tree = self.tree
     for achar in word:
         if achar not in tree:
             tree[achar] = {}
         tree = tree[achar]
     tree["#"] = "#"

 def search(self, word):
     tree = self.tree
     for achar in word:
         if achar not in tree:
             return False
         tree = tree[achar]
     return "#" in tree

 def startsWith(self, prefix):
     tree = self.tree
     for achar in prefix:
         if achar not in tree:
             return False
         tree = tree[achar]
     return True

tmpTrie = 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:   # insert
            aTrie.insert(act[1])
        elif act[0]==2: # search
            aTrie.search(act[1])
        elif act[0]==3: # startsWith
            aTrie.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 ~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VirtualBox+Vagrant安装linux

一、VirtualBox安装 VirtualBox官网&#xff1a;Oracle VM VirtualBox 这里采用VirtualBox--7.0.0 版本 二、Vagrant安装 Vagrant官网&#xff1a;Vagrant by HashiCorp Vagrant镜像仓库&#xff1a;Discover Vagrant Boxes - Vagrant Cloud 这里采用Vagrant--2.4.1版本 在…

【 buuctf-single dog】

单身&#x1f436;&#xff0c;哭死&#xff01; 废话不多说直接 binwalk&#xff0c;果然有 zip&#xff0c;直接提取一下 得到的 1.txt 里面都是些类似表情的东西&#xff0c;是 AAencode 加密&#xff0c;js 颜文字加密CTF在线工具-在线AAencode编码|AA编码|AAencode解码|AA…

vue基础操作(vue基础)

想到多少写多少把&#xff0c;其他的想起来了在写。也写了一些css的 input框的双向数据绑定 html <input value"123456" type"text" v-model"account" input"accou" class"bottom-line bottom" placeholder"请输入…

微服务知识02

1、九大高并发解决方案 2、系统架构图​​​​​​​ 3、分布式事务 本地事务、分布式事务 操作不同服务器的数据库&#xff08;垂直分库&#xff09; 4、分布式事务解决方案&#xff08;没有seata之前&#xff09; &#xff08;1&#xff09;XA协议&#xff08;强一致性&a…

vmware安装centos 7.9 操作系统

vmware安装centos 7.6 操作系统 1、下载centos 7.9 操作系统镜像文件2、安装centos 7.9 操作系统3、配置centos 7.6 操作系统3.1、配置静态IP地址 和 dns3.2、查看磁盘分区3.3、查看系统版本 1、下载centos 7.9 操作系统镜像文件 本文选择centos 7.9 最小化安装镜像包 这里选…

花店行业如何快速搭建自己的小程序

如今&#xff0c;小程序已经成为了各行各业的必备工具之一。对于花店来说&#xff0c;拥有一个专属的小程序能够更好地展示花卉信息&#xff0c;提供在线购买等功能。然而&#xff0c;对于初学者来说&#xff0c;制作小程序可能会感到困惑。但是&#xff0c;不要担心&#xff0…

Spring Security 认证授权安全框架

Spring Security概述 1.什么是Spring Security? Spring Security是一个Java框架&#xff0c;用于保护应用程序的安全性。它提供了一套全面的安全解决方案&#xff0c;包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念&#xff0c;可以轻松地集成到任…

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】顺序表

目录 1 -> 线性表 2 -> 顺序表 2.1 -> 概念及结构 2.2 -> 接口声明 2.3 -> 接口实现 2.3.1 -> 初始化 2.3.2 -> 销毁 2.3.3 -> 检查 2.3.4 -> 打印 2.3.5 -> 尾插 2.3.6 -> 头插 2.3.7 -> 尾删 2.3.8 -> 头删 2.3.9 ->…

【牛客】【刷题节】美团2024届秋招笔试第二场编程真题

1.小美的加法【简单题】 题意理解&#xff1a; 给定一个数组做连加操作&#xff0c;其中只能将一个加号变成乘号 将哪个加号变成乘号&#xff0c;使式子最后的结果最大 解题思路&#xff1a; 只有将两个相邻且乘机最大的数之间变成乘号后&#xff0c;才能保证整个式子结果最大 …

Spring之AOP源码解析(下)

前言 在上一遍文章中,我们主要讲解了ProxyFactory在Spring完成AOP动态代理的过程中发挥的作用。这一篇我们主要讲解这些注解都是如何注入Advisors,然后分析这些Advisors生效的条件 注解都是如何注入Advisor并匹配的 EnableTransactionManagement注解 我们在之前提到EnableT…

乡村研学|乡村研学小程序|基于微信小程序的乡村研学平台设计与实现(源码+数据库+文档)

乡村研学小程序目录 目录 基于微信小程序的乡村研学平台设计与实现 一、前言 二、系统功能设计 三、系统实现 1、微信小程序前台 2、管理员后台 &#xff08;1&#xff09;乡村研学管理 &#xff08;2&#xff09;商品信息管理 &#xff08;3&#xff09;商品类型管理 …

计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号程序员刘同学&#xff0c;回复思科获取下载链接。 实验目的实验环境实验内容MAC地址、IP地址、ARP协议总线型以太网的…

【DAY04 软考中级备考笔记】数据结构基本结构和算法

数据结构基本结构和算法 2月25日 – 天气&#xff1a;晴 周六玩了一天&#xff0c;周天学习。 1. 什么是数据结构 数据结构研究的内容是一下两点&#xff1a; 如何使用程序代码把现实世界的问题信息化如何用计算机高效地处理这些信息从创造价值 2. 什么是数据 数据是信息的…

零基础C++开发上位机--基于QT5.15的串口助手(一)

嵌入式开发的过程中&#xff0c;大部分我们的代码是无法一次成功的。这时候我们大部分的工程师可能最熟练的调试方法是printf函数&#xff0c;打印随意一个数据&#xff0c;来观察当前运行的函数是否执行正确。我们连接的工具有各个大神做的串口助手。另外&#xff0c;在做一般…

从0开始python学习-53.python中flask创建简单接口

目录 1. 创建一个简单的请求,没有写方法时默认为get 2. 创建一个get请求 3. 创建一个post请求&#xff0c;默认可以使用params和表单传参 4. 带有参数的post请求 1. 创建一个简单的请求,没有写方法时默认为get from flask import Flask, request# 初始化一个flask的对象 ap…

【贪心算法】:LeetCode860.柠檬水找零

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本专栏是关于各种算法的解析&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构专栏&…

Ubuntu22.04和Windows10双系统安装

概要 本篇演示Ubuntu22.04和Windows10双系统的安装。先安装Ubuntu22.04&#xff0c;再安装Windows10。 一、说明 1、电脑 笔者的电脑品牌是acer(宏碁/宏基) 电脑开机按F2进入BIOS 电脑开机按F12进入Boot Manager 2、U盘启动盘 需要用到两个U盘启动盘 &#xff08;1&a…

kubernetes集群搭建(1.26版本)

集群搭建 1.初始化安装k8s集群的实验1.1修改主机名称1.2关闭防火墙1.3关闭SELINUX1.4配置主机hosts文件&#xff0c;相互之间通过主机名访问1.5配置主机之间无密码登录1.6关闭交换分区swap&#xff0c;提升性能1.7修改机器内核参数1.9配置阿里云的repo源1.10配置安装k8s组件需要…

力扣● 343. 整数拆分 ● 96.不同的二叉搜索树

● 343. 整数拆分 想不到&#xff0c;要勇于看题解。 关键在于理解递推公式。 1、DP数组及其下标的含义&#xff1a;dp[i]是分解i这个数得到的最大的乘积。 2、DP数组如何初始化&#xff1a;dp[0]和dp[1]都没意义&#xff0c;所以直接不赋值&#xff0c;初始化dp[2]1即可。…

让程序员设计B端界面,好比武大郎招聘:向我看齐。不忍直视!

hello&#xff0c;我是大美B端工场&#xff0c;B端系统的要求越来越高了&#xff0c;很多公司还让程序员负责页面&#xff0c;页面搞的没法看&#xff0c;也怪不得程序员。程序员来搞页面&#xff0c;那还不是武大郎招聘——向我看齐&#xff0c;以我的标准为标准吗&#xff1f…