如果允许预处理,在给定范围的未排序数组中找到最大元素的最快方法是什么。
我们有初始数组A = {3,2,4,5,1},我们需要对它进行预处理,然后我们回答q个查询。
查询示例,如果查询中指定的范围是[0,2],则此范围中的最大元素为4.
答案 0 :(得分:5)
<强>解决方案:强>
我找到了三种解决方案,每种解决方案在某些条件下都有用。他们是:
以下讨论各自的优点和缺点。
<强> 矩阵 强>
要点:
构建一个二维数组M
,M[i][j]
是A[i:j]
中的最大元素。
分析:
当您执行 O(n 2 / log n)查询并且至少 O(n 2)时,此选项最佳)空间。
Space requirement: O(n^2)
Preprocessing time: O(n^2)
Query time: O(1)
伪代码:
class Range {
private M
function Preprocess(A) {
for(i from 0 to n)
M[i][i] = A[i]
for(j from i+1 to n)
M[i][j] = max(M[i][j-1], A[j])
}
function Query(i, j) {
return M[i][j]
}
}
二叉树:
要点:
这是最复杂的选择。您构建了一个树T
,使其
T.root
是A[0:n]
,T.root.left
是A[0:n/2]
,T.root.right
是A[n/2+1:n]
,然后最多有 O(log n)个节点,表示任何给定范围的最大值。
分析:
此选项最适用于 a)您仅限于 O(n)空间或 b)您执行的操作少于< em> O(n 2 / log n)查询。
Space requirement: O(n)
Preprocessing time: O(n)
Query time: O(log n)
伪代码:
class Range {
private T
function Preprocess(A) {
T = BinaryTree({leaves: A})
################################################
# loop over all levels of the tree,
# starting just above the leaves
################################################
foreach(T.levels as level)
foreach(level as node)
node.value = max(node.left.value, node.right.value)
node.leftBound = node.left.leftBound
node.rightBound = node.right.rightBound
}
function Query(i, j) {
nodes = []
currentLeft = T.root
currentRight = T.root
################################################
# search for the left bound of the range,
# keeping any nodes fully contained in the range
################################################
while(currentLeft.leftBound < i)
if(currentLeft.right.leftBound <= i)
currentLeft = currentLeft.right
else
# check if currentLeft.right is fully in the range
if(currentLeft.right.rightBound <= j)
nodes.push(currentLeft.right)
currentLeft = currentLeft.left
if(currentLeft.rightBound <= j)
nodes.push(currentLeft)
################################################
# repeat the above to find the right bound
################################################
while(currentRight.rightBound > j)
...
if(currentRight.leftBound >= i)
nodes.push(currentRight)
################################################
# find the maximum value in nodes
################################################
m = -inf
foreach(nodes as node)
m = max(m, node.value)
return m
}
}
(请注意,给定的伪代码可能会将给定节点添加到nodes
两次,从而导致冗余工作。但是,它总是不会添加超过 O(log n)节点,我不想让伪代码进一步复杂化。)
不要预处理:
要点:
如果您没有进行太多查询,则不应浪费时间进行预处理。
分析:
此选项最适合您进行非常少的查询(围绕 O(1))。
Space requirement: O(n)
Preprocessing time: O(1)
Query time: O(n)
伪代码:
class Range {
private M
function Preprocess(A) {
M = A
}
function Query(i, j) {
m = M[i]
for(k = i+1; k < j; ++k)
m = max(m, M[k])
return m
}
}
答案 1 :(得分:0)
以下是来自@Kittsil's answer的动态编程解决方案(O(n**2)
预处理,O(1)
用于“最大范围内”查询)的实现。要在Python中查找M[start][end] == max(A[start:end])
:
#!/usr/bin/env python
A = [3, 2, 4, 5, 1]
n = len(A)
M = [[None] * (n + 1) for _ in range(n)]
for i in range(n):
for j in range(i, n):
M[i][j + 1] = A[j] if i == j else max(M[i][j], A[j])
测试:
for start in range(n):
for end in range(start + 1, n + 1):
assert M[start][end] == max(A[start:end])