原创水题:Fish 笑传之查查补
本系列为原创垃圾水题,供学校新生天梯赛等算法竞赛以及博君一笑之用。
与其说是算法题,不如说是以模拟为主的思维题。
题目描述
在计算机科学中,Shell 是指一种提供用户与操作系统交互的界面程序。之所以称其为“壳”,是因为它起到“封装”操作系统底层(即 Kernel)的作用,屏蔽用户直接与内核的交互,同时管理用户的命令输入和操作系统的响应。

Shell 通常分为命令行 Shell 和图形 Shell。如 Windows 中的“文件资源管理器”就是一个典型的图形 Shell,允许用户通过图形界面与系统交互。但狭义的 Shell 单指前者,本题中的 Shell 指的是命令行 Shell。
在 Windows 系统中,常见的 Shell 包括 cmd.exe(命令提示符)和 PowerShell。而在 UNIX 系统及其衍生系统中,Shell 的种类更加丰富。以下是几种经典的 UNIX Shell:
sh(Bourne Shell):最初的 UNIX Shell,也是最为经典的版本。ash(Almquist Shell):优化了性能,广泛用于 BSD 系统。bash(Bourne-Again Shell):借鉴了多个 Shell 的功能,成为大多数 Linux 系统的默认 Shell。zsh(Z Shell):对sh做了许多改进,并引入其他 Shell 的特性,自 2019 年起成为 macOS 的默认 Shell。fish(Friendly Interactive Shell):旨在提供更友好的交互体验,拥有智能的命令补全功能,适用于大部分平台。
其中,fish 以其智能、高效的命令补全功能闻名。它不仅能根据可执行文件的名称进行自动补全,还可以基于用户定义的脚本、上下文环境以及历史命令进行动态补全,极大提升了用户的工作效率。下面展示了基于可执行文件和历史命令的补全示例:



Charles 非常喜欢使用 fish,并决定实现一个简化版的动态补全引擎,帮助他在日常工作中快速完成指令补全。这个引擎基于一组预定义的补全规则,能够根据用户输入的前缀迅速返回所有匹配的补全结果。为了满足不同场景的需求,补全规则分为两种类型:
- 全局规则:适用于所有上下文的补全。
- 上下文规则:仅在特定上下文下生效的补全规则。
每条补全规则由以下部分组成:
- 规则类型:全局规则
global或上下文规则context。 - 触发条件(仅适用于上下文规则):规则的适用范围,例如特定命令(如
git)或路径(如/home/charles/)。 - 补全词列表:该规则提供的补全词。
Charles 的引擎需要支持以下功能:
- 根据用户输入的前缀,结合所有匹配的规则,输出补全结果。
- 当全局规则和上下文规则冲突时(即同一前缀的补全结果不同),优先选择上下文规则。
你需要帮助 Charles 实现他的补全引擎,并完成一系列动态补全任务。
输入描述
第一行包含两个整数 $R$ 和 $Q$ $(1 \le R, Q \le 100)$,分别表示补全规则数量和查询数量。
接下来包含 $R$ 条补全规则,每条补全规则的格式如下:
- 第一行为规则类型,可能是全局规则
global或上下文规则context。 - 如果规则是
context类型,接下来一行包含触发条件(一个字符串,表示上下文)。 - 接着是补全词列表:第一行是整数 $n$ $(1 \le n \le 50)$,表示补全词的个数,紧接着是 $n$ 个以空格分隔的补全词。
接下来 $Q$ 行,每行包含一个查询,格式为 上下文 前缀。
其中,若上下文为 . 则表示无上下文(仅适用全局规则),前缀为用户输入的非空字符串。
保证输入的字符串长度均不超过 $127$,不同规则的触发条件可能相同,补全词列表中的词也可能重复。
输出描述
对于每个查询,输出一行,包含去重后的补全结果,按照字典序排列并以空格分隔。
如果没有匹配的补全结果,或输入的命令已经是完整的且无法进行下一步补全,输出 EMPTY。
样例
- 输入数据 1
1 | |
- 输出数据 1
1 | |
- 输入数据 2
1 | |
- 输出数据 2
1 | |
提示
样例解释
对于样例 $1$:
规则解析:
- 第一条规则为全局规则,提供的补全词是:
ls,cd,echo。 - 第二条规则为上下文规则,适用于
git命令,补全词是:add,addon,commit,push。 - 第三条规则为上下文规则,适用于路径
/home/charles/,补全词是:work,personal。 - 第四条规则为全局规则,提供的补全词是:
help,exit。
- 第一条规则为全局规则,提供的补全词是:
查询解析:
查询
. l:- 没有上下文,只有全局规则适用。全局规则提供了补全词
cd,echo,exit,help,ls。 l前缀匹配补全词ls,所以输出:ls。
- 没有上下文,只有全局规则适用。全局规则提供了补全词
查询
git add:- 上下文为
git,适用第二条规则,提供补全词:add,addon,commit,push。 add前缀匹配补全词add和addon,所以输出:add addon。
- 上下文为
查询
git addon:- 上下文为
git,适用第二条规则,提供补全词:add,addon,commit,push。 addon已经是完整的命令,无法继续补全,输出:EMPTY。
- 上下文为
查询
/home/charles/ p:- 上下文为
/home/charles/,适用第三条规则,提供补全词:personal,work。 p前缀匹配补全词personal,所以输出:personal。
- 上下文为
查询
/home/charles/ w:- 上下文为
/home/charles/,适用第三条规则,提供补全词:personal,work。 w前缀匹配补全词work,所以输出:work。
- 上下文为
查询
/home/frex/ x:- 上下文为
/home/frex/,没有对应的上下文规则,只有全局规则适用。全局规则提供了补全词cd,echo,exit,help,ls。 - 没有与
x匹配的补全词,无法进行补全,输出:EMPTY。
- 上下文为
对于样例 $2$:
- 规则解析:
- 第一条规则为全局规则,提供的补全词是:
a,ab,abc,b,bc,bcd。 - 第二条规则为上下文规则,适用于
echo命令,补全词是:a,ac,ak。
- 第一条规则为全局规则,提供的补全词是:
- 查询解析:
- 查询
echo a:- 上下文为
echo,适用第二条规则,提供补全词:a,ac,ak。 a前缀匹配补全词a,ac,ak,所以输出:a ac ak。
- 上下文为
- 查询
echo ac:- 上下文为
echo,适用第二条规则,提供补全词:a,ac,ak。 ac已经是完整的命令,无法继续补全,输出:EMPTY。
- 上下文为
- 查询
echo b:- 上下文为
echo,适用第二条规则,提供补全词:a,ac,ak。 - 没有与
b匹配的补全词,无法进行补全,输出:EMPTY。
- 上下文为
- 查询
. b:- 没有上下文,只有全局规则适用。全局规则提供了补全词
a,ab,abc,b,bc,bcd。 b前缀匹配补全词b,bc,bcd,所以输出:b bc bcd。
- 没有上下文,只有全局规则适用。全局规则提供了补全词
- 查询
ls a:- 上下文为
ls,没有对应的上下文规则,只有全局规则适用。全局规则提供了补全词a,ab,abc,b,bc,bcd。 a前缀匹配补全词a,ab,abc,所以输出:a ab abc。
- 上下文为
- 查询
- 规则解析:
思路
思路?你怕不是在说笑吧?这么大份的题我怎么可能会有思路?
这道题其实是一个经典的字典树 Trie 的简化版本。
核心的数据结构包括:
context:map<string, set<string>>- 存储每个上下文对应的单词集合;-
global:set<string>- 存储全局单词集合(默认上下文)。
补全词去重的工作交给set<string>完成就好。
题解
1 | |