我想知道是否有足够简单的算法来生成N个元素的排列,比如1..N
,它使用的内存少于O(N)
。它不必是计算第n个排列,但它必须能够计算所有排列。
当然,这个算法应该是某种类型的生成器,或者使用一些使用少于O(N)
内存的内部数据结构,因为将结果作为大小为N
的向量返回已经违反了对子线性记忆的限制。
答案 0 :(得分:1)
假设随机排列一次生成一个条目。生成器的状态必须对剩余的元素集进行编码(运行完成),因此,由于不能排除任何可能性,因此生成器状态至少为n位。
答案 1 :(得分:0)
我认为答案必须是" no"。
将N元素排列的生成器视为状态机:它必须包含至少与排列一样多的状态,否则它将在完成所有状态生成之前开始重复。
有N!这样的排列,至少需要ceil(log2(N!))位来表示。 Stirling's approximation告诉我们log2(N!)是O(N log N),因此我们将无法使用子线性内存创建这样的生成器。
答案 2 :(得分:0)
C ++算法next_permutation
执行序列的就地重新排列到其下一个排列中,或者在不存在进一步排列时返回false
。算法如下:
template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last) {
if (first == last) return false; // False for empty ranges.
BidirectionalIterator i = first;
++i;
if (i == last) return false; // False for single-element ranges.
i = last;
--i;
for(;;) {
BidirectionalIterator ii = i--;
// Find an element *n < *(n + 1).
if (*i <*ii) {
BidirectionalIterator j = last;
// Find the last *m >= *n.
while (!(*i < *--j)) {}
// Swap *n and *m, and reverse from m to the end.
iter_swap(i, j);
reverse(ii, last);
return true;
}
// No n was found.
if (i == first) {
// Reverse the sequence to its original order.
reverse(first, last);
return false;
}
}
}
这为生成的每个排列使用常量空间(迭代器)。你认为这是线性的吗?
答案 3 :(得分:0)
我认为甚至存储你的结果(这将是N项的有序列表)将在内存中是O(N),不是吗?
无论如何,要回答你后来随机挑选排列的问题,这里的技术将比生产所有N更好!列表中的可能性,比如说,然后随机选择一个索引。如果我们可以随机选择索引并从中生成相关的排列,我们就会好多了。
我们可以想象您的单词/排列上的字典顺序,并根据单词/排列在字典中的出现顺序将唯一的数字与这些顺序相关联。例如,三个字符的单词将是
perm. index
012 <----> 0
021 <----> 1
102 <----> 2
120 <----> 3
201 <----> 4
210 <----> 5
稍后您会看到为什么最简单的方法是使用我们所做的数字,但其他人可以接受更多的工作。
要随机选择一个,您可以从0 ... N!-1的范围内随机选择其相关索引,并且具有统一的概率(对于即使是中等大的N,我最简单的实现也是不可能的。知道,但我认为有不错的解决方法),然后确定其相关的排列。请注意,列表以最后N-1个元素的所有排列开始,保持第一个数字固定等于0.在这些可能性用尽之后,我们生成所有以1开头的那些。在下一个(N-1)之后!排列耗尽,我们生成那些以2开始的等等。因此我们可以确定前导数字是Floor [R /(N-1)!],其中R是上面所示意义上的索引。现在看看我们为什么零索引?
为了在置换中生成剩余的N-1个数字,假设我们确定Floor [R /(N-1)!] = a0。从列表{0,...,N-1}开始 - {a0}(设置减法)。对于Q = R mod(N-1)!我们想要这个列表的Qth置换。除了考虑到缺少数字这一事实外,这与我们刚刚解决的问题相同。递归。
答案 4 :(得分:0)
也许你可以用事实数字来表达。您可以逐步从中提取结果排列,因此您永远不必将整个结果存储在内存中。
但我开始的原因可能是,我不确定事实数字本身大小的增长行为是什么。如果它适合32位整数或类似的东西,N将被限制为常数,因此O(N)将等于O(1),所以我们必须使用数组,但我不确定它会有多大以N为单位。