题目重点:按可见题名解释同构字符串的一一映射、反例、Unicode 单位和线性解法。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 输入是两个 Python str,以 Unicode 码点序列比较;字符大小写不同,空串与空串同构。题目没有给这些细节。
- 同构要求每个源字符稳定映射到唯一目标字符,并且不同源字符不能映射到同一个目标字符;长度不同直接失败。
解题路线
- 同时维护 source→target 与 target→source 两张映射。扫描相同位置的一对字符:若已有 source 映射必须一致;若是新 source,target 不能已被另一个 source 使用。
- 只做单向映射会误判 `ab` 与 `cc`:a→c、b→c 都能通过,却不是一一映射。两张表各自最多存字符集大小个键。
- 若要按用户感知字素簇而非码点比较,必须先明确 Unicode 分段与规范化;Python 的单字符迭代不会自动把组合字符合成一字素。
手动走一遍
`egg`→`add`:e→a、g→d,第二个 g 仍→d,返回 true。`foo`→`bar`:o 首次→a,第二次却→r,返回 false。`ab`→`cc` 被反向表拒绝。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
"""Training contract: two equal-length Unicode character sequences are isomorphic
iff replacing each distinct source character consistently yields the target.
This is an illustrative implementation; the source post gives only the topic name.
"""
def is_isomorphic(source: str, target: str) -> bool:
if len(source) != len(target):
return False
forward: dict[str, str] = {}
reverse: dict[str, str] = {}
for left, right in zip(source, target):
if left in forward:
if forward[left] != right:
return False
elif right in reverse:
return False
else:
forward[left] = right
reverse[right] = left
return True
复杂度
设字符串长度 N、不同字符数 U,单次遍历 O(N) 期望时间、O(U) 额外空间;哈希表最坏性能依实现。若固定小字符集,数组索引可给确定性 O(N) 时间与 O(|Σ|) 空间。
易错点与追问
容易失分的边界
- 只查 source→target,漏掉反向唯一性。
- 把字符频次相同误认为顺序模式同构。
- 长度不同时 zip 静默截断。
- 未确认大小写、Unicode 规范化和空串语义。
继续深挖
- 只用一张带双向编码的表能否实现?
- 流式接收两串时何时可提前返回 false?
- 大小写不敏感时如何规范化?
- 固定 ASCII 字符集时如何压低常数?
