A
是从1
到n
的整数数组,按随机顺序排列。
我至少需要在日志时间内随机访问第一个i
元素的j
个最大元素。
到目前为止,我提出的是n x n
矩阵M
,其中(i, j)
位置的元素是第一个i
中最大的元素{ {1}}。这为我提供了恒定时间随机访问,但需要j
存储。
通过构造,n^2
按行和列排序。此外,每列与其邻居的区别在于单个值。
有人可以建议使用M
或更好的随机访问时间将M
压缩到n log(n)
空间或更好的方式吗?
答案 0 :(得分:10)
我相信你可以在O(log(N))时间内执行访问,给定O(N log(N))预处理时间和O(N log(N))额外空间。这是怎么回事。
您可以扩充红黑树以支持select(i)
操作,该操作在O(log(N))时间内检索排名i
的元素。例如,see this PDF或算法简介的相应章节。
您可以以功能方式实现红黑树(甚至可以增加一个以支持select(i)
),以便insert操作返回一个新树,该树除了O(log(N))节点之外共享所有节点老树。例如,见Chris Okasaki的Purely Functional Data Structures。
我们将构建一个纯函数增强红黑树的数组T
,以便树T[j]
存储0 ... j-1
个j
元素的索引A
{1}}从最大到最小排序。
基本情况:在T[0]
创建一个只有一个节点的增强红黑树,其数据为数字0,它是数组前1个元素中第0个最大元素的索引{{ 1}}。
归纳步骤:对于从1到A
的每个j
,在N-1
处通过纯函数插入索引为T[j]
的新节点来创建增强的红黑树树j
。这最多创建了O(log(j))个新节点;其余节点与T[j-1]
共享。这需要O(log(j))时间。
构造数组T[j-1]
的总时间是O(N log(N)),使用的总空间也是O(N log(N))。
创建T
后,您可以通过执行T[j-1]
来访问i
元素的j
元素中的A
个最大元素。这需要O(log(j))时间。请注意,您可以在第一次需要时懒惰地创建T[j-1].select(i)
。如果T[j-1]
非常大且A
总是相对较小,这将节省大量时间和空间。
答案 1 :(得分:3)
除非我误解,否则你只是找到一个数组的k-th order statistic,它是另一个数组的前缀。
这可以使用我认为称为“quickselect”的算法或沿着这些行的东西来完成。基本上,它就像快速排序:
Quickselect和Quicker Select标题下有一个(很多)更好的描述here,如果你搜索k阶快速排序解决方案,通常也会在互联网上。
虽然这个算法的最坏情况时间是像快速排序一样的O(n2),但如果你正确选择你的随机枢轴,它的预期情况要好得多(也像快速排序)。我认为空间复杂度只是O(n);你只需制作一个前缀副本就可以搞清楚。