如何判断列表中哪些字符串是经旋转得到的等价字符串?
找出字符串列表中的旋转等价组
核心思路
判断两个字符串是否仅存在旋转差异,最精准且高效的方式是:
- 首先确认两个字符串长度相同(长度不同不可能是旋转关系);
- 检查其中一个字符串是否是另一个字符串与自身拼接后的子串(比如
s2 in s1 + s1)。
为了批量分组,我们可以给每个旋转等价组生成一个唯一标识:取该字符串所有旋转形式中字典序最小的那个作为键,这样同组的字符串会对应同一个键,以此实现快速分组。
实现代码
1. 生成旋转等价标识的函数
def get_rotation_key(s): if not s: return "" # 生成当前字符串的所有旋转形式,取字典序最小的作为分组键 rotations = [s[i:] + s[:i] for i in range(len(s))] return min(rotations)
如果处理超长字符串,可改用更高效的Booth算法(无需生成所有旋转),但上述方法对大部分场景已足够简洁实用。
2. 批量分组处理
from collections import defaultdict # 目标字符串列表 str_list = ['1010', '122a916b2a916b7667110161', '20000000', '2020', '2a916b', '2a916b7667110161122a916b', '6b7667110161122a916b2a91', '916b7667110161122a916b2a', 'ffff'] # 按旋转等价性分组 groups = defaultdict(list) for s in str_list: key = get_rotation_key(s) groups[key].append(s) # 输出结果 for idx, (_, members) in enumerate(groups.values(), 1): print(f"等价组 {idx}:{members}")
为什么比difflib/Levenshtein更优
difflib.SequenceMatcher和Levenshtein.ratio是计算字符串相似度的工具,仅能判断两个字符串是否完全相同(相似度为1),但无法区分“完全相同”和“旋转等价”,且需要两两比较所有字符串,时间复杂度为O(n²),效率较低;- 旋转标识分组法仅需遍历一次字符串列表,时间复杂度为O(n*L)(n为字符串数量,L为单字符串长度),既能精准识别旋转等价组,又能大幅提升处理效率。
示例输出结果
运行上述代码后,会得到以下分组:
- 等价组 1:['1010']
- 等价组 2:['122a916b2a916b7667110161', '2a916b7667110161122a916b', '6b7667110161122a916b2a91', '916b7667110161122a916b2a']
- 等价组 3:['20000000']
- 等价组 4:['2020']
- 等价组 5:['2a916b']
- 等价组 6:['ffff']
内容的提问来源于stack exchange,提问作者user4414119
相关产品推荐
相关产品推荐

