求逆函数:根据给定排列获取其字典序索引
问题分析
你已经实现了从索引生成排列的函数get_nth_permutation,现在需要的是它的逆函数:从排列计算字典序索引。核心思路是把正向过程倒过来,逐步累加每个元素对应的阶乘贡献值。
逆过程的核心逻辑
正向过程中,我们通过index = p_index // factorial(n-1)确定当前选哪个元素,remainder = p_index % factorial(n-1)进入下一层递归。逆过程则是:
- 维护一个当前剩余的原始元素列表(初始是完整的
deck) - 遍历目标排列的每一个元素:
- 找到该元素在当前剩余列表中的位置
k - 计算
k * factorial(len(剩余列表)-1),把这个值加到总索引里 - 从剩余列表中移除这个元素
- 找到该元素在当前剩余列表中的位置
- 遍历完成后,总索引就是所求的字典序索引
伪代码
函数 get_permutation_index(permuted_deck): 剩余列表 = 原始deck的副本(避免修改原列表) 总索引 = 0 对于 permuted_deck 中的每个元素 card: n = 剩余列表的长度 f = (n-1)的阶乘 k = 剩余列表中card的索引位置 总索引 += k * f 从剩余列表中删除card 返回 总索引
Python实现示例
结合你提供的deck列表,实现如下:
import math deck = ["AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC", "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD", "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH", "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS",] def get_permutation_index(permuted_deck): remaining = deck.copy() # 用副本,不修改原deck index = 0 for card in permuted_deck: n = len(remaining) if n == 0: break f = math.factorial(n - 1) k = remaining.index(card) index += k * f del remaining[k] return index # 修正你原函数的可变默认参数问题,避免递归副作用 def get_nth_permutation(p_index, in_list): if p_index >= math.factorial(len(in_list)): return [] if not in_list: return [] f = math.factorial(len(in_list)-1) idx = p_index // f remainder = p_index % f selected = in_list[idx] new_in_list = in_list[:idx] + in_list[idx+1:] return [selected] + get_nth_permutation(remainder, new_in_list) # 测试:生成排列后还原索引 test_index = 123456 perm = get_nth_permutation(test_index, deck.copy()) restored_index = get_permutation_index(perm) print(test_index == restored_index) # 输出True说明逻辑正确
关键注意点
- 避免可变默认参数:你原函数里的
out_list=[]会导致递归时复用同一个列表,多次调用会出错,修正后的get_nth_permutation改用列表拼接方式规避这个问题。 - 大整数处理:52的阶乘是极大的数,但Python的int支持任意精度,不用担心溢出。
- 性能优化:如果需要更快的元素查找,可以提前给
deck建立{card: 原始索引}的字典,把查找位置的时间复杂度从O(n)降到O(1),对于52张牌来说差异不大,但数据量大时效果明显。
内容的提问来源于stack exchange,提问作者ep84
相关产品推荐
相关产品推荐

