当前位置: 首页 > 知识库问答 >
问题:

找到最小的

简烨烁
2023-03-14

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

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

在Jubobs的注释后编辑:例如,如果say数组{12,1,78,90,57,89,56},而kk是3kelements ,最小的元素将是 112。对于第二个 kelements (1,78,90),最小的元素将是 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];    
        }                   
    }
}

共有1个答案

章承基
2023-03-14

您可以使用一个保持排序的队列。

在每个步骤中,如果 deque 中的第一个元素(d.front.index)相对于当前步骤早于 k 个步骤,请弹出它 (d.popFront())。

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

最后,将当前值添加到 deque 的末尾 (d.pushBack())。

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

您可以将 deque 存储为大小为 k 的链接列表。然后,您将始终可以访问其中的第二个元素,这将是[步骤 - k 1,步骤]中的第二个最小元素。如果您最终由于弹出每个元素而只有一个元素,则必须小心。在这种情况下,弹出的那些可能是未来查询的第二小。您可以将这些保留在与 deque 类似的处理方式的另一个列表中,有关示例,请参阅下文。

这是 O(n) 摊销的,因为数组中的每个元素最多只能进入和离开 deque 一次。它可能看起来像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
 类似资料:
  • 我有一个任务需要完成:

  • 输入:p=1,r=55,x=5 产量:5 50 从1到55迭代后,如果数字之和=5,则可能的结果将5,14,23,32,41,50因此输出是一个越来越小的结果 我试着做下面的代码,但我正在从键错误中获取索引。我想这是因为此列表中没有添加任何内容。

  • 我有一组向量,我需要用java编写算法,找到这个集合的最小元素。问题是,有些元素是无与伦比的。例如minset{(1,4,6),(3,2,5),(2,3,4),(5,4,6)} = {(1,4,6),(3,2,5),(2,3,4)}。对于最小元素集“minset”,以下内容成立:原始集的每个向量要么在“minset”中,要么在“minset”中

  • 给出了一系列成本。你可以向前跳两次,也可以向后跳一次。如果你在一个特定的指数上着陆,你必须把成本加到你的总数上。找到穿过数组或到达数组末端所需的最小成本。 输入: 输出: 说明:我们从指数1开始,跳到3然后跳出来,总成本为8 4=12。 我们如何为此构建DP解决方案?

  • 给定一个非负整数数组,设计最简单的算法来找到最大大小的子数组,并将其加到最小的值。 我的想法是,因为它们是非负整数,所以和最小的数组总是单个单元数组,只有原始数组的最小值。如果我理解正确的话,它取决于什么具有更高的优先级,具有更高的长度或更小的值。然而,这个问题从来没有明确说明哪一个优先。 我在这个问题上是正确的,还是我遗漏了什么?

  • 考虑一个问题来寻找区间图的最小支配集。在区间调度的上下文中,它被转换为以下问题: 存在多个可能相互重叠的间隔。找到区间的最小子集,以便对于未包含在子集中的每个区间,它将在与它重叠的子集中找到至少1个区间。 有一个公认的贪婪解决方案可从互联网上的各种来源,例如康奈尔大学的一个解决方案:http://www.cs.cornell.edu/Courses/cs4820/2011sp/handouts/s