特别是在同一类型的一维项目集的域中,例如整数向量。
例如,假设您有一个大小为32,768的向量,其中包含0到32,767的有序整数。
我的意思是“下一个排列”是在词法排序系统中执行下一个排列。
维基百科lists two,我想知道是否还有更多(除了bogo:P)
答案 0 :(得分:7)
O(N)实施 这是基于Eyal Schneider的映射Zn! - > P(n)的
def get_permutation(k, lst):
N = len(lst)
while N:
next_item = k/f(N-1)
lst[N-1], lst[next_item] = lst[next_item], lst[N-1]
k = k - next_item*f(N-1)
N = N-1
return lst
通过将转换步骤与找到置换相结合,减少了他的O(N ^ 2)算法。它基本上与Fisher-Yates具有相同的形式,但在映射的下一步中将随机调用替换为随机。如果映射实际上是一个双射(我正在努力证明),那么这是一个比Fisher-Yates更好的算法,因为它只调用伪随机数发生器一次,因此效率更高。还要注意,这会返回置换的动作(N! - k)而不是置换k,但这没什么影响,因为如果k在[0,N!]上是均匀的,那么N也是如此! - k。
旧回答
这与“下一个”排列的想法有些相关。如果项目可以很好地排序,则可以在排列上构建词典排序。这允许您构建从整数到排列空间的映射。
然后找到随机排列相当于选择0到N之间的随机整数!并构建相应的排列。该算法与计算所讨论的集合的第n个排列一样有效(并且难以实现)。如果我们对n的选择是均匀的,那么这将简单地给出排列的统一选择。
关于排列排列的更多细节。给定一组S = {a b c d}
,数学家将S
的排列组合作为一个组来操作。如果p
是一个排列,让我们说(b a c d)
,那么p
通过将b带到a,a到c,c到d和d到b来对S
进行操作。如果q
是另一种排列,请说(d b c a)
然后pq
首先应用q
然后p
获得(d a b)(c)
。例如,q
将d视为b,p
将b视为a,以便pq
将d视为a。您会看到pq
有两个周期,因为它需要b到d并修复c。习惯上省略1个循环,但为了清楚起见,我将其留下了。
我们将使用群论中的一些事实。
(a b)(c d)
与(c d)(a b)
(a b c) = (b c a) = (c a b)
因此,给定一个排列,对循环进行排序,以便最大的循环首先出现。当两个周期长度相同时,安排他们的项目,以便最大的(我们总是可以订购一个可数集,即使是任意的)项目首先出现。然后我们首先对周期的长度进行词典排序,然后是内容。这是有序的,因为由相同周期组成的两个排列必须是相同的排列,所以如果p > q
和q > p
那么p = q
。
该算法可以在O(N!logN!+ N!)时间内轻松执行。只是构建所有的排列(编辑:只是为了清楚,当我提出这个问题时,我的数学家戴上了帽子,无论如何它都是舌头),快速排序并找到第n个。这是一个与你提到的两个算法不同的算法。
答案 1 :(得分:5)
以下是关于如何改善 aaronasterling 的答案的想法。它避免产生所有N!排列并根据其词典顺序对它们进行排序,因此具有更好的时间复杂度。
在内部,它使用一种不寻常的排列表示,模拟选择&从缩小的数组中删除进程。例如,序列< 0,1,0>表示从[0,1,2]中删除项目#0,然后从[1,2]中删除项目#1,然后从[1]中删除项目#0所产生的排列。得到的排列是< 0,2,1>。利用该表示,第一置换将始终为< 0,0,... 0>,并且最后一个将始终为< N-1,N-2,... 0>。我将这个特殊表示称为“数组表示”。
显然,通过使用数组并在必要时缩小它,可以在O(N ^ 2)时间内将大小为N的数组表示转换为标准置换表示。
以下函数可用于在数组表示中返回{0,1,2 ...,N-1}上的Kth置换:
getPermutation(k, N) {
while(N > 0) {
nextItem = floor(k / (N-1)!)
output nextItem
k = k - nextItem * (N-1)!
N = N - 1
}
}
此算法在O(N ^ 2)时间内工作(由于表示转换),而不是O(N!log N)时间。
- 实施例 -
getPermutation(4,3)返回< 2,0,0>。该数组表示对应于< C,A,B>,它实际上是{A,B,C}上排列的有序列表中索引4处的排列:
ABC
ACB
BAC
BCA
CAB
CBA
答案 2 :(得分:3)
您可以调整合并排序,使其随机调整输入而不是对其进行排序。
特别是,在合并两个列表时,您可以随机选择新的head元素,而不是选择它作为最小的head元素。从第一个列表中选择元素的概率必须为n/(n+m)
,其中n
是第一个的长度,m
第二个列表的长度为此。
我在这里写了详细的解释:Random Permutations and Sorting。
答案 3 :(得分:2)
另一种可能性是建立一个LFSR或PRNG,其周期等于你想要的项目数。
答案 4 :(得分:0)
从排序数组开始。选择2个随机索引,在这些索引处切换元素。重复O(n lg n)次。
您需要重复O(n lg n)次以确保分布接近均匀。 (您需要确保每个索引至少被选中一次,这是一个滚球问题。)