Codewars趣味题#159:中间排列Python代码优化求助——长字符串运行过慢
优化Codewars Simple Fun #159的middle_permutation函数
你的原方案问题在于生成所有排列再排序,当字符串长度为15时,排列数是15!(约1.3e12),完全超出计算和存储的能力范围,必须用数学方法直接构造中间排列,无需遍历所有可能。
核心思路
排列按字典序排序后,中间位置的排列可以通过阶乘计算直接推导每个位置的字符:
- 先将输入字符串按字典序排序(因为排列排序的基准是字典序)
- 计算总排列数的中间索引:
(n! // 2) - 1(和你的原代码逻辑完全对齐) - 逐个确定每个位置的字符:对于剩余的k个字符,每个字符对应
k!种排列,通过中间索引除以k!得到当前要选的字符的索引,更新剩余索引为余数,重复直到所有字符选完
优化后的代码
import math def middle_permutation(string): chars = sorted(string) n = len(chars) mid_index = (math.factorial(n) // 2) - 1 result = [] remaining = chars.copy() k = n - 1 while remaining: fact = math.factorial(k) # 计算当前位置要选的字符索引 idx = mid_index // fact result.append(remaining.pop(idx)) # 更新剩余索引,处理下一个位置 mid_index = mid_index % fact k -= 1 return ''.join(result)
为什么这个方法高效
- 时间复杂度为O(n²):每次从剩余列表中移除字符是O(n),循环n次,对于n=15来说可以瞬间完成
- 空间复杂度为O(n):只需要存储剩余字符和结果,不需要生成任何排列
验证示例
- 输入
"abc":排序后为['a','b','c'],总排列数6,中间索引2。第一个字符选idx=2//2=1(即'b'),剩余索引0,剩余字符['a','c'],下一个字符选0//1=0(即'a'),最后选'c',结果为"bac",和原代码输出一致 - 输入
"abcd":总排列数24,中间索引11,最终会得到"bacd"(和原代码生成排序后第11个元素完全一致)
内容的提问来源于stack exchange,提问作者Devanandh S
相关产品推荐
相关产品推荐

