编辑:
经过进一步思考,可以使用简单的O(n)时间算法,无需RMQ或树(请参见下面我回答的部分)。
给定一个数组A[1...n]和窗口宽度W,需要找到最小的A[i, ...i+W],给定i。
为此,您需要执行以下操作。
将A[1...n]拆分为大小为W-1的连续块。B1、B2、...B(W-1)。
对于每个块B,维护两个名为BStart和BEnd的块。
BStart[i]=B1,B[2],...,B[i]的最小值。
BEnd[i]=B[W-1]、B[W-2]、...、B[W-i]的最小值。
对于每个块,这可以在O(W)时间内完成,因此总共需要O(n)时间。
现在给定一个i,子数组A[i...i+W]将跨越两个连续的块,称为B1和B2。
使用B1End和B2Start分别从i到块B1的末尾和从块B2的开头到i+w中找到最小值。
这是O(1)时间,因此总计O(n)。
对于循环数组C[1....n],您只需要在
A[1....2n]上运行上述操作,这基本上是C连接在一起的两个副本,即A[1...n]=C[1...n]和A[n+1 ... 2n]=C[1...n]
以前的写作。
好的。假设我这次正确理解了您的问题...
可以在O(n)时间和O(n)空间内完成。
实际上,可以将窗口大小更改为任何您喜欢的数字,并针对不同元素使其不同,并仍然使其工作!
给定一个数组A[1...n],可以在O(n)时间和O(n)空间内预处理它,以回答以下形式的查询:在子数组A[i...j]中最小元素的位置是什么?
以常数时间!
这被称为区间最小值查询问题。
因此,从理论上讲,可以在O(n)时间内完成。
仅使用树将为您提供O(nlogW)时间,其中W是窗口的大小,并且在实践中可能比RMQ更好,因为我认为隐藏的常数可能会使RMQ更糟。
您可以按如下方式使用树。
从后往前插入W个元素。找到最小值并将其推入堆栈。然后删除第一个元素并插入(W+1)th元素。再次寻找最小值并将其推入堆栈。以此类推。总处理时间为O(nlogW)。
最终,你会得到一个最小值的堆栈,当你第二次按正确顺序遍历数组时,你可以继续弹出这些最小值,直到找到0.95*target。
另外,你的问题不是很清楚,你说它是一个循环缓冲区,但你似乎没有使用长度进行模运算。而且,按照编写的方式,你的算法的复杂度是O(n),而不是O(n^2),因为窗口大小是一个常数。
numberOfDataPointsInPast
是你的数组大小吗? - phimuemue如果当前值比先前值低5%
,但在你的代码中,实际上是在计算数据点的数量。因此存在差异。事实上,你的代码计算的是最后n个数据点之前的n个数据点中,至少比当前参考数据点低5%的数据点数量。 - Frerich Raabe