【问题标题】:Constructing array from given array with some constraints使用一些约束从给定数组构造数组
【发布时间】:2012-02-18 17:38:48
【问题描述】:

给定一个包含 N 个元素的数组 A[0 .. N - 1],生成一个数组 B 使得:

 B[i] = min (A[i], A[i+1], ..., A[i+K-1]). 

(数组 B 正好有 (N-k+1) 个元素。

时间复杂度应该优于 O(N*k)

我在考虑使用 minheap...但是 heapify 会增加复杂性 蛮力也是 O(n*k)

空间复杂度也小于等于 O(k)

这是一个例子

Input: 
A={ 2,1,3,2,5,7,1}, N=7,k=3

Output:
B={1,1,2,2,1}

【问题讨论】:

  • 问题是什么? O(N*k) 是否正确?
  • 没有必要将“should”缩写为“s'd”。让你的问题难以阅读并没有给自己带来任何好处。
  • 不,O(n*k) 不正确。我也更新了问题
  • 已经理解并发布了答案

标签: algorithm


【解决方案1】:

解决问题可以使用queue in which push_rear(), pop_front() and get_min() are all constant time operations

将数组 A 中的第一个 k 元素推送到此队列。然后继续从数组A 填充队列,同时从中弹出元素并将最小值附加到数组B

时间复杂度为O(N)。空间复杂度为O(k)

【讨论】:

    【解决方案2】:

    在 O(N) 而不是 O(N*k) 中这样做的关键是不计算给定的公式 B[i] = min (A[i], A[i+1], ..., A[i+K-1]) 用于每个条目,但会逐步更新。

    在每一步都有一个K 排序条目的结果集。

    第一步:从前 K 个条目计算 B[0],并将结果分配给 B[0]

    第一步: 计算B[1],您只需将A[i+K] 添加到结果集中并从结果集中减去A[0],而不是重新添加K 个条目。

    每一个增量步骤: 因此,对于每个附加索引,您的结果集只有两次更新。

    总的来说,你有线性复杂度。

    【讨论】:

    • 添加或插入? ...你是如何计算最小值的?
    • 更新你的页面。我“添加”澄清“添加”不是“+”而是“添加到结果集”
    • 你是如何在 O(1) 的排序列表中将新项目插入到排序列表中查找项目的排序列表中的?
    • @OleGG 不在 O(1) 中。在排序的随机访问数据结构中添加一个条目是 O(log(n))
    • 因此 in 不会是线性的,总复杂度将是 O(n*log(n))
    【解决方案3】:

    步骤 1

    编写一个具有“减少键”功能的(最低)优先级队列。这意味着您可以转到一个节点(例如通过指针),减少它的值并更新堆(优先队列)。

    操作decrease_key 将是O(log(k))k 是优先级队列中的元素数。

    第二步

    考虑以下操作:

    • Add A[i]:这包括将A[i] 添加到优先级队列中,以及保持一个指针,例如C[i],指向在优先级队列中创建的节点。这是O(log(k))

    • Remove A[i]:这意味着转到包含A[i](通过C[i])的节点,将其值减小到负无穷大,然后将其从堆顶移除。这也是O(log(k))

    第三步

    初始化优先队列:将A的第一个k元素添加到优先队列中。这是O(k*log(k))

    第四步

    像这样填充B的元素:

    for i = 1 to n-k+1
        B[i] = pQ.top
        Remove A[i]
        Add A[i+k]
    

    这部分是O(n*log(k))

    最终分析

    这个算法的总时间顺序是O(n*log(k))。空间顺序是O(k)。这是优先级队列的k 节点和指向这些节点(数组C)的k 指针,如果天真地实现,它们将变为O(n)

    【讨论】:

    • 您的第二步将产生指针问题,因为由于优先级的变化,它们将被打乱? ...或者你可以在给定的测试用例上运行你的算法
    • 指针,而不是索引。以不移动对象而是移动它们的引用的方式编写队列。
    【解决方案4】:

    来自我之前的回答:Finding maximum for every window of size k in an array,其中列出了四种不同的 O(n) 解决方案。

    0) 通过结合两个经典的面试问题,可以得到 O(n) 时间的解决方案:

    • 在 O(1) 时间内创建一个支持 push、pop 和 max 的堆栈数据结构(称为 MaxStack)。

      这可以使用两个堆栈来完成,第二个堆栈包含目前看到的最小值。

    • 用堆栈建模队列。

      这可以使用两个堆栈来完成。入队进入一个堆栈,而出队来自另一个堆栈。

    对于这个问题,我们基本上需要一个队列,它支持在O(1)(摊销)时间内入队、出队和最大值。

    我们通过使用两个 MaxStack 对队列建模,将上述两者结合起来。

    为了解决这个问题,我们对 k 个元素进行排队,查询最大值,出队,入队 k+1 个元素,查询最大值等。这将为您提供每个 k 大小的子数组的最大值。

    我相信还有其他解决方案。

    1)

    我相信队列的想法可以简化。我们为每个 k 维护一个队列和一个最大值。我们将一个新元素入队,并将所有不大于新元素的元素出队。

    2) 维护两个新数组,维护每个 k 块的运行最大值,一个数组用于一个方向(从左到右/从右到左)。

    3) 使用锤子:在 O(n) 时间内进行范围最大查询的预处理。

    上面的 1) 解决方案可能是最优化的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多