【问题标题】:Permutations unrank排列未排序
【发布时间】:2015-07-29 14:05:21
【问题描述】:

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

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

【问题讨论】:

标签: algorithm language-agnostic permutation


【解决方案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 雷姆 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;
}

【讨论】:

    猜你喜欢
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    • 2019-10-26
    • 2017-05-16
    相关资源
    最近更新 更多