给定一组数字a[0], a[1], ..., a[n-1]
,我们得到了类似的查询:
输出k
- a[i], a[i+1], ..., a[j]
可以在每个查询的多对数时间(n
)内回答这些查询吗?如果没有,是否可以平均结果并仍然获得良好的摊销复杂性?
编辑:这可以使用持久性细分树来解决 http://blog.anudeep2011.com/persistent-segment-trees-explained-with-spoj-problems/
答案 0 :(得分:4)
是的,如果O(n log n)
空间可用,可以在多字录时间内回答这些查询。
通过构造深度为log(n)
的分段树来预处理给定的数组。因此,叶子节点与源数组相同,下一个深度节点包含已排序的2个元素子数组,下一个级别包含通过合并这些2个元素数组生成的4个元素数组,等等。换句话说,执行合并排序但是将每个合并步骤的结果保存在单独的数组中。这是一个例子:
root: | 1 2 3 5 5 7 8 9 |
| 1 2 5 8 | 3 5 7 9 |
| 1 5 | 2 8 | 7 9 | 3 5 |
source: | 5 | 1 | 2 | 8 | 7 | 9 | 5 | 3 |
要回答查询,请将给定范围(最多2 * log(n)个子范围)拆分。例如,范围[0, 4]
应该分为[0, 3]
和[4]
,这会提供两个排序的数组[1 2 5 8]
和[7]
。现在问题被简化为在几个排序的数组中找到第k个元素。解决它的最简单方法是嵌套二进制搜索:首先使用二进制搜索从每个数组中选择一个候选元素,从最大的一个开始;然后在其他(较小的)数组中使用二进制搜索来确定此候选元素的等级。这允许在O(log(n)^4)
时间内获得第k个元素。可能一些优化(如分数级联)或其他一些算法可以更快地做到这一点......
答案 1 :(得分:0)
有一个基于快速排序的名为QuickSelect的算法。它的平均情况是O(n)。当输入有序时,算法的最坏情况是O(n ** 2)。
它给出了确切的第k个最大数字。如果你想要范围,你可以编写一个包装器方法。