我在CS.SE问过这个问题,但没有回复。
我最近面临以下面试问题:
给定一个数组A和一个整数k,找到一个连续的子数组 最大总和,加上约束,此子阵列的长度最多为k。
因此,如果A=[8, -1, -1, 4, -2, -3, 5, 6, -3]
,我们会针对k
的不同值获得以下答案:
+---+------------------------------+
| k | subarray |
+---+------------------------------+
| 1 | [8] |
| 7 | [5,6] |
| 8 | [8, -1, -1, 4, -2, -3, 5, 6] |
+---+------------------------------+
如果n
是数组A
的长度,那么使用修改后的优先级队列,我能够及时回答这个问题O(n lgk)
;有没有办法将其改进为O(n)
?请注意,当k = n时,Kadane算法在O(n)
时运行。
答案 0 :(得分:4)
你可以在O(n)中完成。这是怎么回事。
B
B[x] = sum(i in (0, x+1), a[i])
w<=q
,q-w <=k
和B[q] - B[w]
是可能的最大值。 为此,我们将通过数组B找到q。由于B[q]
已修复,因此当B[w]
为最小值时,我们会最大化表达式。我们保持双端队列以快速找到w。双端队列将保留潜在最小值的位置。要更新它:取出第一个元素,因为它超出了你想要的k间隔,从后面提取所有值,这些值大于当前位置的值,最后在后面插入当前位置。
应该是这样的
for (q in len(b))
// The minimum is too far behind
if !deque.empty() && q - deque.front() > k: deque.pop_front()
// Remove the less optimal positions from the queue.
while (!deque.empty() && b[deque.back()] > b[q]) deque.pop_back()
deque.push_back(q)
if (b[q] - b[deque.front()] > best_so_far) UpdateBestSoFar();
它可能看起来像O(N ^ 2),因为内部虽然但不是。每个元素一次插入双端队列并提取一次。所以迭代的总数是O(N)。