所有现有答案都需要检查矩阵中的每个单元格。如果您还不知道最大值的位置是什么,这是不可避免的,在这种情况下,Amit Kumar's BFS algorithm 具有最佳时间复杂度:O(wh),如果矩阵的宽度为 w 和高度为 h。
OTOH,也许你已经知道k个最大值的位置,而k相对较小。在这种情况下,以下算法将在 O(k^2*(log(k)+log(max(w, h)))) 时间内找到答案,当 w 或 h 很大时,这要快得多。它实际上并不查看 any 矩阵条目;相反,它运行二进制搜索来寻找候选停止时间(即答案)。对于每个候选停止时间,它会构建一组届时将被max 占据的矩形,并检查是否有任何矩阵单元未被矩形覆盖。
为了解释这个想法,我们首先需要一些术语。将矩形的顶行称为“开始垂直事件”,将其底边下方的行称为“结束垂直事件”。 “基本间隔”是由任何一对垂直事件跨越的行的间隔,它们之间没有第三个垂直事件(定义这些间隔的事件对可以来自相同或不同的矩形)。请注意,对于 k 个矩形,基本间隔不能超过 2k+1 个——这里不依赖于 h。
基本思想是从左到右遍历矩阵中对应于水平事件的列:新矩形“开始”的列(左垂直边缘)矩形)或现有矩形“完成”(矩形右垂直边缘右侧的列),跟踪当前覆盖每个基本间隔的矩形数量。如果我们检测到一个由 0 个矩形覆盖的基本区间,我们可以停下来:我们发现一列包含一个或多个在时间 t 尚未覆盖的单元格。如果我们在没有发生这种情况的情况下到达矩阵的右边缘,那么所有单元格都在时间 t 被覆盖。
这是一个函数的伪代码,用于检查是否有任何矩阵单元在时间t 之前未被覆盖,给定一个长度为k 的数组peak,其中(peak[i].x, peak[i].y) 是第i 个包含max 的位置原始矩阵中的单元格,按 x 坐标的升序排列(因此最左边的包含max 的单元格位于(peak[1].x, peak[1].y))。
Function IsMatrixCovered(t, peak[]) {
# Discover all vertical events and basic intervals
Let vertEvents[] be an empty array of integers.
For i from 1 to k:
top = max(1, peak[i].y - t)
bot = min(h, peak[i].y + t)
Append top to vertEvents[]
Append bot+1 to vertEvents[]
Sort vertEvents in increasing order, and remove duplicates.
x = 1
Let horizEvents[] be an empty array of { col, type, top, bot } structures.
For i from 1 to k:
# Calculate the (clipped) rectangle that peak[i] will cover at time t:
lft = max(1, peak[i].x - t)
rgt = min(w, peak[i].x + t)
top = max(1, peak[i].y - t)
bot = min(h, peak[i].y + t)
# Convert vertical positions to vertical event indices
top = LookupIndexUsingBinarySearch(top, vertEvents[])
bot = LookupIndexUsingBinarySearch(bot+1, vertEvents[])
# Record horizontal events
Append (lft, START, top, bot) to horizEvents[]
Append (rgt+1, STOP, top, bot) to horizEvents[]
Sort horizEvents in increasing order by its first 2 fields, with START considered < STOP.
# Walk through all horizontal events, from left to right.
Let basicIntervals[] be an array of size(vertEvents[]) integers, initially all 0.
nOccupiedBasicIntervalsFirstCol = 0
For i from 1 to size(horizEvents[]):
If horizEvents[i].type = START:
d = 1
Else (if it is STOP):
d = -1
If horizEvents[i].col <= w:
For j from horizEvents[i].top to horizEvents[i].bot:
If horizEvents[i].col = 1 and basicIntervals[j] = 0:
++nOccupiedBasicIntervalsFirstCol # Must be START
basicIntervals[j] += d
If basicIntervals[j] = 0:
return FALSE
If nOccupiedBasicIntervalsFirstCol < size(basicIntervals):
return FALSE # Could have checked earlier, but the code is simpler this way
return TRUE
}
上面的函数可以简单地在对 t 的二分查找中调用,查找函数返回 TRUE 的 t 的最小值。
通过使用Fenwick trees,可以利用受任何矩形开始或结束影响的基本区间集始终是一个区间这一事实,可以去除进一步的 k/log(k) 因子。