给定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)
空间复杂度s'd也小于等于O(k)
这是一个例子
Input:
A={ 2,1,3,2,5,7,1}, N=7,k=3
Output:
B={1,1,2,2,1}
答案 0 :(得分:4)
要解决此问题,您可以使用queue in which push_rear(), pop_front() and get_min() are all constant time operations。
将数组k
中的第一个A
元素推送到此队列。然后继续从数组A
填充队列,同时从中弹出元素并将最小值附加到数组B
。
时间复杂度为O(N)
。空间复杂度为O(k)
。
答案 1 :(得分:0)
在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个条目。
每增加一步: 因此,对于每个附加索引,您只有两个结果集更新。
总的来说,你有线性的复杂性。
答案 2 :(得分:0)
编写具有“减少键”功能的(最小 - )优先级队列。这意味着您可以转到节点(例如通过指针),减少其值并更新堆(优先级队列)。
操作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))
初始化优先级队列:将k
的第一个A
元素添加到优先级队列中。这是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
个节点和指向那些节点的k
指针(数组C
),如果天真地实现,它们将成为O(n)
。
答案 3 :(得分:0)
从我之前的回答:Finding maximum for every window of size k in an array,其中列出了四种不同的O(n)解决方案。
0)通过结合两个经典的面试问题,可以实现O(n)时间解决方案:
创建一个堆栈数据结构(称为MaxStack),在O(1)时间内支持push,pop和max。
这可以使用两个堆栈完成,第二个堆栈包含到目前为止看到的最小值。
使用堆栈建模队列。
这可以使用两个堆栈来完成。入队进入一个堆叠,出列的是另一个。
对于这个问题,我们基本上需要一个队列,它在O(1)(摊销)时间内支持入队,出队和最大。
我们通过使用两个MaxStack建模队列来结合上述两个。
为了解决这个问题,我们对k个元素进行排队,查询max,dequeue,将第k + 1个元素排队,查询max等。这将为每个k大小的子数组提供最大值。
我相信还有其他解决方案。
1)
我相信队列的想法可以简化。我们为每个k维护一个队列和一个最大值。我们将一个新元素排入队列,并将所有不大于新元素的元素取消。
2)保持两个新阵列,每个k块保持运行最大值,一个阵列为一个方向(从左到右/从右到左)。
3)使用锤子:在O(n)时间内预处理以进行范围最大查询。
上述1)解决方案可能是最优化的。