题目重点:把所有字符可经同一循环位移转换的字符串归为一组,处理跨z/a边界、单字符和空串。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 小写ASCII字母,位移逐字符同一offset并模26;不同长度不能属于同组。
- 输出组与组内顺序采用首次遇见顺序;不按组大小排序。空串自成一个等价类,与单字符不同。
解题路线
- 以首字符为原点,把每个字符归一为(ord(c)−ord(first)) mod26,所得元组是分组key。
- 若两词相同key,首字符差定义一个shift,所有位置差都相同;反之整体shift会保持这些相对差,证明key充要。
- 空串key=(),单字符key=(0,),所以不会混;负差模26处理如za与ab,不能只做普通整数差。
手动走一遍
abc/bcd/xyz同key(0,1,2),az/ba同key(0,25),a/z同key(0),空串单独归组。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def group_shifted_strings(words):
"""Lowercase ASCII; all strings in a group differ by a uniform cyclic shift."""
groups={}
for word in words:
if any(c not in 'abcdefghijklmnopqrstuvwxyz' for c in word):
raise ValueError('lowercase ASCII required')
key=tuple((ord(c)-ord(word[0]))%26 for c in word) if word else ()
groups.setdefault(key,[]).append(word)
return list(groups.values())
复杂度
O(总字符数)预期时间,O(总字符数)key与输出引用空间;hash成本也与词长相关。
易错点与追问
容易失分的边界
- 只比较相邻差不加入长度或边界规则,会错误混空串与单字符;完整元组长度天然编码长度。
- 普通差−25与1应模26等价,否则za/ab被分开。
继续深挖
- 若字母表改自定义有序字符集,模数与映射要一致;Unicode全域没有默认循环顺序。
- 允许位移加反转时,需要对原词key与反转key选择规范代表,不能直接沿用单方向等价。
