SWE · Coding

Meta 循环移位字符串分组:模二十六归一化

把所有字符可经同一循环位移转换的字符串归为一组,处理跨z/a边界、单字符和空串。

题目重点:把所有字符可经同一循环位移转换的字符串归为一组,处理跨z/a边界、单字符和空串。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 小写ASCII字母,位移逐字符同一offset并模26;不同长度不能属于同组。
  • 输出组与组内顺序采用首次遇见顺序;不按组大小排序。空串自成一个等价类,与单字符不同。

解题路线

  1. 以首字符为原点,把每个字符归一为(ord(c)−ord(first)) mod26,所得元组是分组key。
  2. 若两词相同key,首字符差定义一个shift,所有位置差都相同;反之整体shift会保持这些相对差,证明key充要。
  3. 空串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选择规范代表,不能直接沿用单方向等价。
✓已复制微信号!