华子这题确实不错!

2023-10-30

我们来看一下这道题目到底哪里不错。

题目描述

小王在进行游戏大闯关,有一个关卡需要输入一个密码才能通过,密码获得的条件如下:在一个密码本中,每一页都有一个由 26 个小写字母组成的若干位密码,从它的末尾开始依次去掉一位得到的新密码也在密码本中存在。请输出符合要求的密码,如果由多个符合要求的密码,则返回字典序最大的密码。若没有符合要求的密码,则返回空字符串。

输入

密码本由一个字符串数组组成,不同元素之间使用空格隔开,每一个元素代表密码本每一页的密码。

输出

一个字符串

示例一

输入

h he hel hell hello

输出

hello

说明

"hello" 从末尾依次去掉一位得到的 "hell", "hel", "he", "h"在密码本中都存在。

示例二

输入

b eredderd bw bww bwwl bwwlm bwwln

输出

bwwln

解题思路

最朴素的解法是将所有字符串都存在一个哈希表password_set中,然后遍历字符串数组中的每一个密码password,对每一个password都去判断其所有的前缀是否也位于password_set中。如果满足,则把passwordans比较并且更新ans

这种做法虽然思路直接简单,但略显笨重,会出现很多重复计算。

以示例一为例子:

  • 对于单词hell,需要分别考虑前缀hhehel

  • 对于单词hello,需要分别考虑前缀hhehelhell

  • 前缀hhehel对于单词hello而言,显然是重复计算了。

  • 假设我们已经知道单词hell是一个有效的密码,那么对于单词hello,我们就只需要去考虑hell这个前缀,而不需要再去考虑hhehel这三个前缀了。

  • 换句话说,单词hello是否是一个有效的密码,可以由其去掉末尾的前缀hell是否是一个有效的密码来决定。这本质上是一种动态规划的思想。(动态规划更详细的内容在后面会讲到)

如果用动态规划的语言来描述,即:password是一个有效密码,****当且仅当password[:-1]是一个有效密码。

那么现在问题就变成了:如何能够在判断password是一个有效密码之前,就先判断得到password[:-1]**是否有效?**这个问题就很简单了。我们只需要对原来的字符串数组password_lst按照字典序进行排序,就可以保证在password进行判断时,password[:-1]已经被判断过了。

我们可以构建一个用于储存所有有效密码的哈希集合valid_set。然后遍历排序过的字符串数组password_lst中的每一个密码password,如果其去掉末尾的前缀password[:-1]位于valid_set中,说明password也是一个有效密码,需要将其加入valid_set中,同时更新ans

for password in password_lst:
    if password[:-1] in valid_set:
        valid_set.add(password)
        ans = password

注意valid_set初始化时要包含一个空串"",因为只有一个字符的密码比如"h",去掉最末尾的字符之后是一个空串"""h"理应是一个有效的密码,故""应该存在于valid_set中。即:

valid_set = {""}

代码

解法一

(哈希集合暴力解法,只能通过部分用例)

# 题目:2023Q1A-寻找密码
# 作者:许老师
# 代码看不懂的地方,请直接在群上提问,不要过夜!

# 将输入字符串分割为字符串数组,并且存入哈希集合中
password_set = set(input().split())
# 初始化答案为一个空字符串
ans = str()

# 遍历哈希集合password_set中的所有密码单词password
for password in password_set:
    # password有可能不符合要求,设置一个标记isValid,初始化为True表示该密码符合要求
    isValid = True
    # 遍历password的所有前缀password[:i],判断前缀是否均位于password_set中
    for i in range(1, len(password)-1):
        # 若某一个前缀不位于哈希集合中,则该password无效,修改isValid为False,且退出循环
        if password[:i] not in password_set:
            isValid = False
            break
    # isValid为True,说明该password有效,将其与ans比较并更新ans
    if isValid:
        ans = max(ans, password)

print(ans)

时空复杂度

时间复杂度:O(NM)。遍历每个单词、每个字符所需的时间。

空间复杂度:O(NM)

N为单词数目,M为单词平均长度。

解法二

(哈希集合优化解法,含DP思想,可以通过全部用例)

# 题目:2023Q1A-寻找密码
# 作者:许老师
# 代码看不懂的地方,请直接在群上提问,不要过夜!

password_lst = input().split()
# 对输入的字符串数组进行升序排序
password_lst.sort()

# 初始化一个表示有效密码的哈希集合,初始化其中仅包含空字符串
valid_set = {""}
# 初始化答案为空字符串
ans = ""

# 从头到尾遍历升序字符串数组password_lst中的密码password
for password in password_lst:
    # 如果password去掉最后一位的结果password[:-1],位于valid_set哈希集合中
    # 说明当前的password是一个有效密码,将其加入valid_set,同时更新ans
    if password[:-1] in valid_set:
        valid_set.add(password)
        ans = password

print(ans)

时空复杂度

时间复杂度:O(NlogN)。排序所需的时间复杂度。

空间复杂度:O(NM)。哈希集合所占的额外空间。

N为单词数目,M为单词平均长度。

解法三*

(前缀树解法,不要求掌握,感兴趣的同学可以研究一下)

# 题目:2023Q1A-寻找密码
# 作者:许老师
# 代码看不懂的地方,请直接在群上提问,不要过夜!

# 前缀树的节点类
class Trie():
    def __init__(self) -> None:
        self.children = [None] * 26
        self.isEnd = False

    # 将单词word加入前缀树的函数
    def addword(self, word):
        node = self
        for ch in word:
            ch_idx = ord(ch) - 97  # ASCII to idx
            # 以下两行用来通过最后一个用例..输入了非小写字母的字符串
            if ch_idx > 25 or ch_idx < 0:
                return
            if node.children[ch_idx] is None:
                node.children[ch_idx] = Trie()
            node = node.children[ch_idx]
        node.isEnd = True

    # 检查word的所有前缀是否存在的函数
    def checkPrefix(self, word):
        node = self
        for ch in word:
            ch_idx = ord(ch) - 97
            if node.children[ch_idx].isEnd == False:
                return False
            node = node.children[ch_idx]
        return True


if __name__ == "__main__":
    lst = input().split()
    ans = ""

    root = Trie()
    for word in lst:  # 构建前缀树
        root.addword(word)

    for word in lst:
        if len(word) < len(ans):
            continue
        if root.checkPrefix(word):
            if len(word) > len(ans):
                ans = word
            elif len(word) == len(ans):
                ans = max(ans, word)
    print(ans)

时空复杂度

时间复杂度:O(NM)。建树、检查前缀的时间。

空间复杂度:O(D)

N为单词数目,M为单词平均长度,D为前缀树的节点数,远小于NM


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

华子这题确实不错! 的相关文章

  • 使用ESP8266 12-E板载的CH340对ESP01-s进行烧录

    先借两张图 因为ESP01 S的烧录器找不到了 临时用ESP8266 12 E板载的CH340对ESP01 s进行烧录 1 12 E的EN引脚接地G 2 ESP01 s的3v3连接12 E的3v3 3 ESP01 s的GND连接12 E的G
  • 【左神算法课学习笔记】动态规划

    左神算法课学习笔记 动态规划 动态规划是对暴力递归算法的优化 主要是通过数组记录的方法 优化掉一些重复计算的过程 总结下动态规划的过程 1 抽象出一种 试法 递归解决问题的方法 很重要 2 找到 试法 中的可变参数 规划成数组表 可变参数一
  • 蓝桥杯官网练习题(李白打酒)

    题目描述 本题为填空题 只需要算出结果后 在代码中使用输出语句将所填结果输出即可 话说大诗人李白 一生好饮 幸好他从不开车 一天 他提着酒壶 从家里出来 酒壶中有酒2斗 他边走边唱 无事街上走 提壶去打酒 逢店加一倍 遇花喝一斗 这一路上
  • 查看python环境路径_查看python环境的一些知识点

    1 查看python中的查找模块的路径import sys sys path usr bin usr lib64 python26 zip usr lib64 python2 6 usr lib64 python2 6 plat linux
  • CDC处理——异步FIFO

    1 异步FIFO原理 请看 硬件架构的艺术 笔记 三 3 8节 异步FIFO 2 格雷码传递FIFO读写指针 回环特性 通常情况下 设计的异步FIFO的深度是2的N次方 但事实上 选择这个2 N的原因也是因为格雷码这么取的时候 最大值 1回
  • S4 MB5B 结算库存数量与 MMBE 中的数量不同

    用户在查询库存过程中发现MB5B 结算库存数量与 MMBE 中的数量不同 我们知道MMBE是系统的当前库存 MB5B是可以根据输入的日期查询输入日期当天的库存 MMBE查询库存数量为971米 再来看MB5B库存 输入物料 工厂 日期为今天2

随机推荐

  • 在Windows10上安装虚拟机---VMware 17 Pro下载与安装

    在Windows10上安装虚拟机 VMware下载与安装 0 前言 1 下载VMware 17 pro 2 安装VMware 17 Pro 3 打开Vmware 0 前言 电脑原生系统 Windows10 虚拟机软件 VMware 17 p
  • ORACLE随机查询

    1 select from select from tablename order by dbms random value where rownum lt N 注 dbms random是一个可以生成随机数值或者字符串的程序包 value
  • 训练模型的3种方法

    公众号后台回复关键字 Pytorch 获取项目github地址 Pytorch没有官方的高阶API 一般通过nn Module来构建模型并编写自定义训练循环 为了更加方便地训练模型 作者编写了仿keras的Pytorch模型接口 torch
  • STM8普通定时器中断使用寄存器版本

    本文章只讲如何使用STM8的普通定时器 原理以及其他知识点可以网上查阅相关的资料 废话不多说 直奔主题 第一步 了解TIM4的时钟来源 查阅书册可以知道TIM4的时钟来源系统的主时钟 第二步 初始化相关寄存器 从ST官方手册可以知道 TIM
  • Spring Boot的文件上传

    Spring Boot的文件上传并不需要单独进行 当前端进行请求时 所要上传的文件作为请求的一个参数即可 与其他类型参数相同 服务端接收时 只需要对这个文件参数使用MultipartFile类型接收即可 由于文件上传的参数无法直接拼接到UR
  • unplugin-vue-components/vite自动将项目中使用的 Vue 组件按需引入

    unplugin vue components 是一个 Vite 插件 它可以自动将项目中使用的 Vue 组件自动按需引入 以减小打包体积 它的使用方式如下 安装插件 npm install D unplugin vue component
  • 上拉和下拉的解释

    1 什么是上下拉电阻 上拉电阻 把一个不确定的信号通过电阻连接到高电平 是电信号初始化为高电平 下拉电阻 把一个不确定的信号通过电阻连接到地 使电信号初始为低电平 本质 上拉是对器件注入电流 下拉是输出电流 2 上下拉电阻接线方法 上拉电阻
  • Kafka 消费者“group_name”组正在永远重新平衡

    目录 一 场景 1 1 场景应用环境 1 2 问题重现 二 问题分析 三 解决方案 一 场景 1 1 场景应用环境 卡夫卡 2 11 1 0 1 主题 并发度为 5 且分区为 5 1 2 问题重现 当应用程序重新启动并且在分区分配之前在主题
  • MySQL获取分组中的第一条数据和最后一条数据

    mysql 8 WITH ranked messages AS SELECT m ROW NUMBER OVER PARTITION BY name ORDER BY id DESC AS rn FROM messages AS m SEL
  • 《C++11标准库》4.2头文件( Header File)

    在C 标准化过程中 将C 标准库中所有的标识符都定义于 namespace std 内 这样的作法不具备向后兼容性 因为原先的C C 头文件都将C 标准库的标识符定义于全局范围 标准化过程中有些 class 接口也有了变动 为此 C sta
  • vscode 变量命名插件_10款VS Code插件神器,第7款超级实用!

    VS Code是这两年非常热门的一款开发工具 它不仅有提升开发体验的界面 轻量化的编辑器 还有丰富而强大的插件 这些优秀的插件使得VS Code生态体系更加吸引人 让开发效率大大提升 本文来介绍10款高效的VS Code插件 总有一款能够惊
  • iOS 使用“./compile-ffmpeg.sh all”编译 ijkplayer 报错“C compiler test failed.

    原因 compile ffmpeg sh 脚本找不到 Xcode 解决方案 compile ffmpeg sh clean sudo usr bin xcode select switch Applications Xcode app Co
  • 微信小程序相关面试题

    微信小程序相关面试题 1 请谈谈wxml与标准的html的异同 2 请谈谈WXSS和CSS的异同 3 请谈谈微信小程序主要目录和文件的作用 4 请谈谈小程序的双向绑定和vue的异同 5 简单描述下微信小程序的相关文件类型 6 微信小程序有哪
  • 未竟的Web 3.0理想,DID或打开关键入口

    寄托往往意味着断送 维克多 雨果 悲惨世界 里的经典之言正是Web2 0时代的写照 近期 B站 答题领卡兑换大会员 活动被网友指出涉嫌出卖用户个人隐私 虽然B站回应称 该页面系文案措辞不妥引起误会 目前已下线该页面并整改 但风波并没有止息
  • 未预期的符号 `then’ 附近有语法错误加粗样式

    未预期的符号 then 附近有语法错误加粗样式 编写shell脚本执行时发生如下报错 后经分析 错误原因是因为if后面没有加空格 加入空格之后则不再存在语法错误 修改后脚本截图
  • 重启人生1.0-day1:704. 二分查找;27. 移除元素

    数组理论基础 704 二分查找 左闭右闭区间 left right size len nums left 0 right size 1 while left lt right 当left right的时候 循环区间是个合法区间 middle
  • dataguard-(ORA-16004/ORA-01196/ORA-01110)

    author skatetime 2009 08 01 1 故障现象 一次突然断电导致我的standby open时报如下的错误 ORA 16004 备份数据库需要恢复ORA 01196 文件 1 由于介质恢复会话失败而不一致ORA 011
  • Unity Text 透明

    Unity Text透明化问题 Shader UI TextBlend Properties HideInInspector MainTex Texture 2D white HideInInspector BlendTex Blend T
  • 集度汽车(武汉java)一面

    hashMap底层结构 hash算法的好处是什么 为什么采用数组加链表 数组有哪些特性 内存地址连续 查找快 怎么解决哈希碰撞 链地址法 并发编程需要注意哪些地方 如何处理变量的线程安全 sycronized关键字原理 分布式锁实现方式 有
  • 华子这题确实不错!

    我们来看一下这道题目到底哪里不错 题目描述 小王在进行游戏大闯关 有一个关卡需要输入一个密码才能通过 密码获得的条件如下 在一个密码本中 每一页都有一个由 26 个小写字母组成的若干位密码 从它的末尾开始依次去掉一位得到的新密码也在密码本中