繁体   English   中英

在大小为N的数组的每k个元素中找到最小和第二个最小元素

[英]Find smallest & second smallest element in every k elements of an array with size N

我试图在N大小的数组的k个元素中找到最小和第二个最小的元素(没有排序和最小/最大堆)。

使用传统方法,首先从第0个元素开始,然后在前k个元素中找到最小和第二个最小元素,然后将起点移动1然后重复该过程。 但是它的复杂度是O(Nk) 如果可能,我需要一个复杂度为O(N)的解决方案。 有什么建议吗?

在Jubobs评论后编辑:例如,如果说array为{12, 1, 78, 90, 57, 89, 56} 12,1,78,90,57,89,56 {12, 1, 78, 90, 57, 89, 56}并且k3 ,则对于前k元素(12, 1, 78)最小元素将为1 ,第二个最小元素元素将是12 对于第二k元素(1, 78, 90) ,最小元素为1 ,第二最小元素为78 ,依此类推。

以下是我编写的具有O(Nk)复杂度的代码段:

int j=0;
while(j < input.length-k+1) {
    int i=j;
    for(i=j; i < j+k; i++) {
        if(input[i] < min) {
            min2 = min;
            min = input[i];
        } else if(input[i] > min && input[i] < min2) {
            min2 = input[i];    
        }                   
    }
}

您可以使用保持排序的双端队列

在每个步骤中,如果双端队列中的第一个元素( d.front.index )相对于当前步骤早于k步,则将其弹出( d.popFront() )。

然后,尽管数组中当前位置的元素小于双端队列的最后一个元素( d.back.value ),但双端队列的弹出元素( d.popBack() )。

最后,将当前值添加到双端队列( d.pushBack() )的末尾。

在每个步骤中, d.front.value将是[step - k + 1, step]的最小值。

您可以将双端队列存储为大小为k的链表。 然后,您将始终可以访问其中的第二个元素,这将是[step - k + 1, step]第二小的元素。 如果由于弹出每个元素而最终只包含一个元素,则必须小心。 在这种情况下,弹出的查询可能是将来查询中第二小的查询。 您可以将它们保留在与双端队列类似的其他列表中,请参阅以下示例。

这是O(n)摊销的,因为数组中的每个元素最多将进入和离开双端队列。 可能看起来像O(nk)因为您将有一些嵌套循环,但是如果考虑操作总数,您会发现它实际上是O(n)

伪代码

for i = 0, i < n:
    if not d.empty and i - d.front.index >= k:
      d.popFront()
    while not d.empty and d.back.value > a[i]:
      d.popBack()

    d.pushBack({index = i, value = a[i]})

    output d.front.value as the minimum value in [i - k + 1, i]

跟踪第二最小值的代码仍作为练习。

例如:

a = {12, 1, 78, 90, 57, 89, 56}, k = 3

d = {12}
d = {1} (12 popped, track this)
d = {1, 78} => we have to output smallest and second smallest in [0, 2].
            => smallest is always the first in the deque, so 1
            => second = min(12 [this was popped], 78) = 12
d = {1, 78, 90)
            => smallest 1, second is 78 (12 is too old now)
d = {57}
            => 1 popped for being too old, the others for being too large
            => smallest = 57, second = 78 (last popped)
d = {57, 89}
            => smallest = 57, second = 89
d = {56}
            => smallest = 56, second = 57

基本上,您将数组保留为第二个最小的数组。 这将包含尚未过时的弹出值。 这些也将排序,但降序排列。

为此方法运行的示例,其中d2是第二个数组:

a = {12, 1, 78, 90, 57, 89, 56} 

d = {12},           d2 = {}
d = {1},            d2 = {12}
d = {1, 78},        d2 = {12}
  => output 1, 12
d = {1, 78, 90},    d2 = {} - 12 was too old
  => output 1, 78
d = {57}            d2 = {90, 78}
  => output 57, 78
d = {57, 89}        d2 = {90} - 78 too old
  => output 57, 89 (if we had 91 instead of 89, we'd have output the 90 in d2)
d = {56}            d2 = {89, 57}
  => output 56, 57

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM