通过率 49% · 提交 508 · 通过 247
小慕正在开发一个项目,项目中有一个模块需要输入一个密钥才能解锁,密钥的获取规则如下:在一个密钥库中,每个条目都是一个由 26 个小写字母组成的若干位密钥,从它的末尾开始依次去掉一位得到的新密钥也在密钥库中存在。请输出符合要求的最长密钥,如果有多个符合要求的密钥,则返回字典序最大的密钥。若没有符合要求的密钥,则返回空字符串。
这类题属于华为 OD 机考真题方向中「100分 / 2023A」方向的高频题型,通常考察对「100分 / 2023A」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
提示:带虚线的词点一下有通俗解释。
密码本由一个字符串数组组成,不同元素之间使用空格隔开,每一个元素代表密码本每一页的密码。
一个字符串
示例 1
输入示例
h he hel hell hello
输出示例
hello
"hello" 从末尾依次去掉一位得到的 "hell", "hel", "he", "h"在密码本中都存在。
示例 2
输入示例
b eredderd bw bww bwwl bwwlm bwwln
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
相关图解步骤
先看指定步骤补关键知识点,再回到本题完成标准输入输出。
最朴素的解法是将所有字符串存在一个哈希表 password_set 中,然后遍历字符串数组中的每一个密码 password,对每一个 password 都去判断其所有的前缀是否也位于 password_set 中。如果满足,则把 password 和 ans 比较并且更新 ans。
这种做法虽然思路直接简单,但略显笨重,会出现很多重复计算。
以示例一为例子:
hell,需要分别考虑前缀 h、he、helhello,需要分别考虑前缀 h、he、hel、hell前缀 h、he、hel 对于单词 hello 而言,显然是重复计算了。
假设我们已经知道单词 hell 是一个有效的密码,那么对于单词 hello,我们就只需要去考虑 hell 这个前缀,而不需要再去考虑 h、he、hel 这三个前缀了。
换句话说,单词 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。
注意 valid_set 初始化时要包含一个空串 "",因为只有一个字符的密码比如 "h",去掉最末尾的字符之后是一个空串 "","h" 理应是一个有效的密码,故 "" 应该存在于 valid_set 中。即:
(哈希集合暴力解法,只能通过部分用例)
复杂度分析
设密钥库中有 n 个密钥,最长密钥长度为 L。
以参考代码(解法一,哈希集合暴力解)为准:
正文中的改进思路(先按字典序排序,再用 valid_set 只检查“去掉末尾一位”的前缀)把每个密钥的校验从最多 L-1 次前缀查找降为 1 次:排序是 O(n log n * L)(字符串比较最坏 O(L)),随后一趟遍历中每个密钥只做一次 O(L) 的切片与哈希查找,共 O(n*L)。总时间 O(n log n * L),空间同样是 O(n*L),明显优于暴力解。
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
输出示例
bwwln
时间限制 1000 ms · 内存限制 128 MB
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有