如何计算第 n 个排列(或告诉给定排列的字典顺序)?

How can I calculate n-th permutation (or tell the lexicographic order of a given permutation)?

这个问题有两个部分,但由于我正在尝试完成 Prolog 实现,解决一个问题可能会立即导致另一个问题的解决方案。

  1. 给定一个整数列表 {1,2,...,N} 的排列,我如何知道该排列在字典序中的索引是什么?
  2. 给定一个数字 k,我如何计算数字 {1,2...,N} 的第 k 次排列?

我正在寻找一种算法,它可以比仅迭代 next permutation 函数 k 次更好地完成此操作。 Afaik 应该可以直接计算这两个。

到目前为止我想出的是,通过查看左边的数字,我可以知道在特定索引处每个数字之前有多少排列,然后以某种方式将它们组合起来,但我不太确定如果这导致正确的解决方案。

想想有多少排列以数字 1 开头,有多少排列以数字 2 开头,等等。假设 n = 5,则 24 个排列以 1 开头,24 个排列以 2 开头,依此类推。如果您正在寻找排列,比如 k = 53,则有 48 个以 1 或 2 开头的排列,因此 #53 是以 3 开头的排列中的第五个。

在以 3、6 开头的排列中,每个排列都以 31、32、34 或 35 开头。所以您正在寻找以 (3, 1) 开头的第五个排列。有两个排列,每个排列都以 312、314 和 315 开头。因此,您正在寻找以 315 开头的两个排列中的第一个。即 31524。

将其转化为代码应该很容易。

我将给出每个解决方案的概要:

Given a permutation of a list of integers {1,2,...,N}, how can I tell what is the index of that permutation in lexicographic ordering?

为此,问问自己有多少排列以 1 开头?有(N - 1)!。现在,让我们做一个例子:

3 1 2

有多少 1 2 312 开头的排列? 2*2!。这个肯定在那些之后,所以它的索引至少是2*2! = 4。现在检查下一个元素。 1 2 有多少种排列以 0 开头? None。大功告成,索引为 4。如果您想使用基于 1 的索引,您可以添加 1

Given a number k, how can I calculate k-th permutation of numbers {1,2...,N}?

给定4,我们如何得到3 1 2?我们必须找到每个元素。

第一名能有什么?如果我们有 1,最大索引可以是 2! - 1 = 1(我使用的是从零开始的索引)。如果我们有2,最大可以是2*2! - 1 = 3。如果我们有3,最大值可以是5。所以我们必须有 3:

3

现在,我们已经将问题简化为找到 1 2 的第 4 - 2*2! = 0 次排列,即 1 2(您可以像上面那样递归推理)。

你也可以看看阶乘数系统,尤其是关于permutations的部分。对于给定的数字k,你首先应该找到它的阶乘表示,然后很容易给出所需的排列(实际上,(k+1)-st排列)。

k=5 和数字 {1,2,3} 的示例:

5 = 2*2! + 1 * 1! + 0*0! = (210)_!

所以 5 的阶乘表示是 210。现在让我们将该表示映射到排列中。我们从有序列表 (1,2,3) 开始。我们的阶乘表示中最左边的数字是 2,所以我们正在寻找列表中索引为 2 的元素,即 3(列表是从零开始索引的)。现在我们只剩下列表 (1,2) 并继续该过程。我们的阶乘表示中最左边的数字,在去掉 2 之后,是 1,所以我们得到索引 1 处的元素,也就是 2。最后,我们只剩下 1,所以 (k+1)-st (6th) 排列{1,2,3} 是 {3,2,1}。

尽管理解它需要一些时间,但它是一种非常高效的算法并且易于编程。反向映射类似。