gpt4 book ai didi

C++:在子数组的数组中查找最大整数

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:16:04 24 4
gpt4 key购买 nike

我面临一个问题,我想编写一个算法,该算法可以返回更大数组中每个连续的 k 元素子数组的最大元素,并将这些最大元素读入它们自己的数组,如下所示:

Given int array = {3, 7, 20, 6, 12, 2, 0, 99, 5, 16}, and int k = 4,
--> creates the array {20, 20, 20, 12, 99, 99, 99}
[because there are 7 consecutive sub-arrays of size 4 within the given array:
{3, 7, 20, 6}, {7, 20, 6, 12}, {20, 6, 12, 2}, ... , {0, 99, 5, 16}
and the max element of these, respectively, is 20, 20, 20, ..., 99 which
are read into the resulting array.

现在这是我的问题:我知道如何在 O(n^2) 复杂度中实现它,但想使其更快,以便它可以是 O(n),或者如果那是不可能,O(nlog(n))。有谁知道是否有更快的方法来做到这一点,如果有,怎么做?

最佳答案

首先,朴素算法的复杂度是O(k(n-k+1))(通常这近似于O(k.n)),不是O(n^2)。在这里,对于每个连续的子数组(n-k+1 可能),您必须执行 k 比较。

通过一些内存,您可以做得比这更好,使用一个长度为 k 的额外数组,我们可以称之为 maximums。该数组将存储下一个最大值的索引。

对于数据集的每次迭代,您都会检查 maximums 的第一个元素。您删除所有“过期”索引,现在第一个元素是当前迭代的答案。

当您在数据上滑动一个窗口(大小 k)时,您将当前索引推到 maximums,然后按如下方式修剪它:索引 maximums[i] 必须 小于索引 maximums[i-1] 处的值。如果不是,则继续将索引冒泡到 maximums 的开头,一次一个点,直到这变为真。

实际上,最好将maximums 数组视为环形缓冲区。修剪过程会将尾部缩回头部,同时弹出任何“过期”最大值(当窗口滑过它们时)将使头部前进一步。

它有点笨拙,但这里有一些工作代码来说明:

#include <vector>
#include <iostream>

int main()
{
const int window_size = 4;
std::vector<int> vals = { 3, 7, 20, 6, 12, 2, 0, 99, 5, 16 };
std::vector<int> maximums( window_size );
int mhead = 0, mtail = 0;

for( int i = 1; i < vals.size(); i ++ )
{
// Clean out expired maximum.
if( maximums[mhead] + window_size <= i )
{
int next_mhead = (mhead + 1) % window_size;
if( mtail == mhead ) mtail = next_mhead;
mhead = next_mhead;
}

if( vals[i] >= vals[ maximums[mtail] ] )
{
// Replace and bubble up a new maximum value.
maximums[mtail] = i;
while( mhead != mtail && vals[ maximums[mtail] ] >= vals[ maximums[(mtail+window_size-1)%window_size] ] )
{
int prev_mtail = (mtail + window_size - 1) % window_size;
maximums[prev_mtail] = maximums[mtail];
mtail = prev_mtail;
}
}
else
{
// Add a new non-maximum.
mtail = (mtail + 1) % window_size;
maximums[mtail] = i;
}

// Output current maximum.
if( i >= window_size - 1 )
{
std::cout << vals[ maximums[mhead] ] << " ";
}
}

std::cout << std::endl;
return 0;
}

现在,时间复杂度...

最好的情况是 O(n),如果您的所有数据都已排序(升序或降序),就会发生这种情况。

我认为,最坏的情况是 O(2n)。在一次迭代中需要 k 额外操作的唯一方法是如果您已经有 k 线性复杂度的步骤(以便环形缓冲区已满)。在这种情况下,下一步的环形缓冲区将为空。由于我们只能填充和清空环形缓冲区 n/k 次,因此那些偶尔的 k 操作会在 k.n/k 时出现,或者只是 < strong>n.

您应该能够证明,即使环形缓冲区的持续部分清空也会导致相同的复杂性。

最后,我们可以总结并称整个事情为 O(n),因为对于大的 n,任何常数因子都变得无关紧要。结果实际上比我预期的要好。 =)

关于C++:在子数组的数组中查找最大整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35401653/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com