题目重点:从字符串每个字符位置选或不选,生成去重的子序列,最后按字典序排序;说明与字符重排的区别。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版对每个字符下标选择/不选择,保留被选字符在原字符串的相对顺序;包含空子集。
- 输出按 Python 字符串字典序排序并去除重复结果;若原题按长度或 locale 排序、允许重复下标组合,需改合同。
- 字符视为代码点;大小写是否合并题目未明确,训练版不合并。
解题路线
- 从集合 {空串} 开始,依次处理原字符串每个字符;新集合是旧集合与‘旧集合每串追加当前字符’的并集。
- 每一步不改变已有子序列的内部字符顺序,因此生成的都是原输入某些下标组成的合法子序列;所有选/不选路径都会被遍历,集合去除重复结果。
- 最后对集合排序输出,不能先对输入字符排序:输入 'ba' 的合法两字符结果是 'ba',不是 'ab'。
- 若 n 大,输出本身最多有 2^n 个不同结果,必须问是否有输出上限或只要求迭代器;想减少内存可按字典序生成但重复字符与原顺序约束更复杂。
手动走一遍
'ba' 的结果为 ['', 'a', 'b', 'ba'];把输入排序成 'ab' 会错误地产生 'ab'。'aa' 两个下标子集都能产生 'a',训练版只输出一次,因此 ['', 'a', 'aa']。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
"""Distinct index-subsequences of a string, sorted lexicographically."""
def sorted_distinct_subsets(text: str) -> list[str]:
result = {""}
for character in text:
result.update(prefix + character for prefix in list(result))
return sorted(result)
复杂度
n 个字符最多 2^n 个结果,每次构造字符串最多 O(n),总 O(n·2^n) 时间与 O(n·2^n) 字符存储;最终排序至多 2^n 项,比较成本另计。输出指数级是不可避免的下界。
易错点与追问
容易失分的边界
- 先把字符排序再生成,破坏原下标子序列语义。
- 未问重复字符是否去重、空集是否包括,就宣称原题唯一答案。
- 生成完按长度排而题目只说 sorted,未澄清排序键。
- 声称可在多项式时间列出指数数量结果。
继续深挖
- 若重复下标选择应分别保留,输出怎样表达身份?
- 若只要字典序前 K 个子序列,如何避免完整枚举?
- Unicode 组合字符与代码点顺序如何定义?
