优化具有许多元素和不同标准的数组

Optimizing array that has many elements and different standards

我有一个将 X 作为参数并从二维数组中随机选取一个元素的函数。 二维数组有上千个元素,每个元素对X都有不同的要求,存储在arr[Y][1].

例如,

解决这个问题的最佳方法是什么 space,元素重复最少?

最糟糕的方法是将每个 X 的可能选择存储在二维数组中。但是这样会造成很多重复,占用太多内存。

然后,我想过用三个数组,把X+要求,X-和X范围分开。但这对我来说还是太基础了,有没有更好的方法?

这里的一个选项是所谓的 "accept/reject sampling":您选择一个随机索引 i 并检查该索引是否满足 X 上的条件。如果是这样,你 return arr[i]。如果没有,你随机选择另一个索引并重复直到找到一些东西。

只要满足大多数i值的大多数条件,性能就会很好。如果不是这种情况——如果有很多 X 的值只满足很少的条件——那么尝试预先计算一些东西可能是有意义的这可以让你找到(或缩小)给定 X.

允许的索引

如何做到这一点取决于您允许什么作为每个索引的条件。例如,如果每个条件都由您给出的示例中的间隔给出,您可以对列表进行两次排序,首先按左端点,然后按右端点。然后确定特定 X 值的有效索引归结为将左端点小于或等于 X 的区间与右端点大于或等于 X 的区间相交。

当然,如果您允许 "X is in this interval" 以外的条件,那么您需要不同的算法。

虽然我相信重新采样将是您的最佳解决方案(数十次重新采样的代价非常低),但这是我在实践中永远不会实现的算法(因为它使用非常复杂的数据结构和效率低于重采样),但具有可证明的界限。每个查询需要 O(n log n) 预处理时间、O(n log n) 内存和 O(log n) 时间,其中 n 是您可能采样的元素数。

您将所有范围的所有端点存储在一个数组中(称之为 ends)。例如。在你的情况下你有一个数组 [-infty, 4, 37, 59, 79, +infty] (它可能需要一些调整,比如在范围的右端添加 +1 ;现在不重要)。这个想法是,对于任何 X 我们只需要确定它位于哪一端之间。例如。如果 X=62[59; 79] 范围内(我将这样的对称为 interval)。然后对于每个间隔,您存储一组所有可能的范围。对于您的输入 X 您只需找到区间(使用二进制搜索),然后输出一个随机范围,对应于该区间。

如何计算每个间隔的相应范围集?我们在 ends 数组中从左到右。假设我们计算当前间隔的集合,然后转到下一个。这些间隔之间有一些结束。如果它是某个区间的左端,我们将相应的范围添加到新集合中(因为我们输入了这个范围)。如果它是右端,我们删除范围。我们如何在 O(log n) 时间内而不是 O(n) 内做到这一点?不可变平衡树集可以做到这一点(本质上,它们创建新树而不是修改旧树)。

如何 return 从集合中获得均匀随机的范围?您应该扩充树集:每个节点都应该知道其子树包含多少个节点。首先,您对 [0; size(tree)) 范围内的整数进行采样。然后查看根节点及其子节点。例如,假设您采样了整数 15,并且您的左子树的子树大小为 10,而右子树的大小为 20。然后您转到右子树(因为 15 >= 10)并用整数 5 处理它(因为 15 - 10 = 5).您最终将访问对应于单个范围的叶子。 Return这个范围。

抱歉,如果难以理解。就像我说的,在最坏的情况下,这不是你需要上限的简单方法(之前讨论的其他方法在最坏的情况下需要线性时间;如果没有元素满足限制,重新采样可能 运行 无限期) .它还需要一些小心处理(例如,当某些范围具有重合的端点时)。