排列不受欢迎

时间:2015-07-29 14:05:22

标签: algorithm language-agnostic permutation

我知道一种算法(可以在网上找到)对排列进行排名,即给定排列将整数索引返回到按字典顺序排列的排列列表,但我不知道任何 unrank 执行相反的算法:给定索引i,返回该词典顺序中的第i个排列。

由于我找不到任何东西,有人可以解释一下吗?

1 个答案:

答案 0 :(得分:1)

假设您正在排列字母(a,b,c)。

有3×2×1 = 6个排列。其中,第三个以a开头,按字典顺序排在另一个三分之一前面,以b开头,最后三分之一以c开头。

对于这些三分之一中的每一个都有两个,一个从选择第一个后面的第一个字母开始,另一个是第二个。

这些一半中只有一个元素(最后一个字母)。

因此,给定一组三个元素以及一个介于0和5之间的索引(假设3),我们可以将(通过提醒)除以每个“第三个”的大小来得到第一个字母。现在:

  • 该集合的大小为n = 3
  • 有n!= 6个排列
  • 存在n = 3组排列,其以n个元素中的每一个开始
  • 每组的大小为n!/ n =(n-1)! = 6/3 = 2个元素

为了确定第一个元素的索引,我们用余数除以2:

3÷2 = 1 rem 1

由于我们的集合是(a,b,c),这告诉我们第一个字母是b

现在,我们可以从集合中删除字母b,并使用提醒作为新索引。我们得到集合(a,c)和索引1.重新应用算法,

  • 该集合的大小为n = 2
  • 有n!= 2个排列
  • 存在n = 2组排列,其以n个元素中的每一个开始
  • 每组的大小为n!/ n =(n-1)! = 2/2 = 1个元素

要确定第一个元素的索引,我们用余数除以1:

1÷1 = 1 rem 0

由于我们的集合是(a,c),这告诉我们第一个第二个字母是c

第三组缩减为单身a,这是我们的第三个字母。

索引3的排列是b,c,a。

我们来检查一下:

0 abc
1 acb
2 bac
3 bca <-- correct!
4 cab 
5 cba

所以,把它放在一个真实的算法中并概括:

public string NthPerm(string set, int n)
{
    var res = "";
    while (set.Length > 0)
    {
        var setSize = Math.Factorial(set.Length-1);
        var index = n/setSize;

        res.Concat(set[index]);

        set = index > 0 ? set.Substring(0, index) : "" +
              index < set.Length-1 ? set.Substring(index+1) : "";

        n = n % setSize;
    }
    return res;
}