【问题标题】:Maximal subarray with length constraint具有长度约束的最大子数组
【发布时间】:2020-09-24 08:25:48
【问题描述】:

我在 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)?请注意,Kadane 的算法在 k=n 时运行在O(n) 时间。

【问题讨论】:

  • 如果将要跟踪的数组的大小限制为 k,Kadane 的算法会如何失败?
  • @G.Bach:当 k=7 时,尝试对问题中的数组执行此操作。当您到达5 时,以[8, -1, -1, 4, -2, -3, 5] 结尾的最大数组。但是,当您移动到6 时,您需要删除8;这会导致连锁反应删除-1, -1, 4, -2, -3,因为长度最多为7 的最大子数组,以6 结尾,是[5,6]。换句话说,您需要在遍历数组时跟踪要“丢弃”哪些元素,而简单的实现会导致时间与 n*k 成正比。
  • 你确定?你会有两个指针,一个左一个右,每个指针都会遍历数组一次,不是吗?
  • @G.Bach:我很想了解它的工作原理。不过,我看不出如何通过修改 Kadane 的算法来做到这一点:有 k 个子数组可以在任何给定元素(长度为 1、2、...、k)处停止,并且遍历它们都需要 n*k .

标签: arrays algorithm max


【解决方案1】:

你可以在 O(n) 中完成。方法如下。

  • 让我们定义数组B 的部分和B[x] = sum(i in (0, x+1), a[i])
  • 现在问题变成了查找索引 q 和 w 使得 w<=qq-w <=kB[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),但事实并非如此。每个元素在双端队列中插入一次,并且只提取一次。所以while迭代的总次数是O(N)。

【讨论】:

  • 我相信这是正确的,但值得一提的是,您保持双端队列中列出的位置对应于 B[] 的非递减值的不变量 - 这使您可以确信deque.front() 始终是产生最小值的位置,而不必搜索双端队列中的每个元素来寻找最小的位置。
  • 这太棒了!这也与我的做法非常相似:我本质上是在修复 w 并寻找最佳 q。为此,我维护了一个堆,以便我可以快速获得最大 B[q]。这个答案不仅是正确的,而且改进了我原来的解决方案。
  • 你确定吗?你怎么能保持增加B 的不变性?以 op 为例,您将拥有B == [0, 8, 7, 6,10 ...]。这听起来不正确。
  • 哦,是的。我得到了它。天哪,太聪明了。
  • 对于那些希望了解更多关于这种双端队列技术的人来说,它被称为最小/最大队列,并在此类问题中找到其最基本的用例。
猜你喜欢
  • 2021-12-21
  • 1970-01-01
  • 2023-01-25
  • 2022-11-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2012-10-22
相关资源
最近更新 更多