题目重点:针对 onsite 提供 next() 类和 one//ntw 等分块示例,逐字符保留分隔符前缀,恢复完整行并验证随机切块。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版把题目描述中写出的 //n 当成三字符行分隔标记;若面试现场实际是转义后的换行符,应把 delimiter 改为 '\n'。
- next_chunk() 返回 str 或在结束时返回 None;空字符串只是空 chunk。连续分隔符代表空行;末尾只有分隔符时不额外输出空行。
解题路线
- 逐字符读取 chunk,维护当前行字符和 pending 分隔符前缀。pending 可能跨多个 chunk 保留,不能在 chunk 末尾直接输出。
- 新字符使 pending 不再是分隔符前缀时,依次把不可能组成分隔符的前导字符转入当前行;若 pending 完整等于分隔符,就输出一行并清空。
- EOF 时将未完成的 pending 当普通内容追加,输出非空残行;若流正好停在分隔符后,不凭空增加一行。
- 训练实现可接受任意非空 delimiter;固定短 delimiter 情况逐字符处理接近线性,复杂长 delimiter 可使用 KMP 自动机。
手动走一遍
chunks=['one//ntw','o//n','three//nfour','//nfi','ve'] 拼起来是 one//ntwo//nthree//nfour//nfive,依次输出 one、two、three、four、five;第一个 chunk 末尾的 tw 必须等后续 o 才成 two。若分隔符在 '/' 与 '/n' 之间切开,也能识别。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
"""Parse a multi-character line marker across arbitrary next() chunks."""
def read_lines(next_chunk, delimiter: str = "//n"):
if not delimiter:
raise ValueError("delimiter must be nonempty")
line = []
pending = ""
while True:
chunk = next_chunk()
if chunk is None:
break
for character in chunk:
pending += character
while pending and not delimiter.startswith(pending):
line.append(pending[0])
pending = pending[1:]
if pending == delimiter:
yield "".join(line)
line = []
pending = ""
line.extend(pending)
if line:
yield "".join(line)
复杂度
设总字符数 T、分隔符长度 D、最长一行 L;展示版前缀检查最坏 O(T·D²)(D=3 时按常数看 O(T)),当前行与 pending 占 O(L+D)。输出所有行本身需 O(T) 总字符。KMP 可把任意长分隔符优化到 O(T+D)。
易错点与追问
容易失分的边界
- 对每个 chunk 独立 split,跨块分隔符和单词会被拆错。
- 忽略 Python/Java split 对尾部空串的行为差异。
- 把示例的 //n 未经说明地换成实际换行字符。
- 在 EOF 时丢掉没有末尾分隔符的残行。
继续深挖
- 连续两个分隔符是否要输出空行?
- 如果 next() 可能返回极长且无分隔符的 chunk,如何控制内存?
- 分隔符很长且前后缀重叠时,怎样用 KMP 保证线性扫描?
