给定一个数组,我想计算给定时间窗口内值的最大绝对差值。
例如,如果数组是股票价格列表,那么这个问题可以被认为是“在w
大小的时间窗口内价格的最大涨幅或降幅是多少?”
下面是一个用于说明问题的小例子。
# Example array and window size.
w = 4 # window size
arr = [49, 51, 45, 42, 42, 46, 49, 49, 50, 53, 54]
# Desired output.
max_diff_in_window = -9 # 42 - 51 = -9 is the largest absolute difference within a time window of 4.
index_start = 1 # 51, the first value to appear from our largest absolute difference pair, is located at index 1.
index_finish = 3 # 42, the second value to appear from our largest absolute difference pair, is located at index 3.
在此示例中,请注意整个数组中值的最大绝对差值为11(53-42)。但是,这不是正确的解决方案,因为它不遵守4的指定窗口大小。
我认识到这个问题与Maximum single-sell profit问题有一些相似之处,但有一些重要的区别。首先,是时间窗口的介绍。其次,我正在寻找最大的绝对差异,这对应于最大的利润或亏损,而不是最大的利润。
我尝试过蛮力解决方案,但现在正试图确定一种更有效的方法。是否有针对此问题的已知动态编程解决方案?
答案 0 :(得分:2)
这可以使用this answer的动态编程方法解决,只需稍加修改即可添加滑动窗口。
好消息:它仍然是O(n)
。坏消息:由于minima" expire",我们需要一个队列来存储它们,这会将空间复杂度增加到O(w)
,其中w
是窗口大小。
def gain(arr, w):
q_min = collections.deque()
q_max = collections.deque()
d = 0
a = 0
b = 0
# loop over all windows of the array of length w (i denotes the endindex)
for i in range(len(arr)):
# update the queue holding the minimum within the current window
while q_min and q_min[0] <= i - w:
q_min.popleft()
while q_min and arr[i] <= arr[q_min[-1]]:
q_min.pop()
q_min.append(i)
# update the maximum held within the current window
while q_max and q_max[0] <= i - w:
q_max.popleft()
while q_max and arr[i] >= arr[q_max[-1]]:
q_max.pop()
q_max.append(i)
# check if current minimum makes up for the maximum difference so far
if abs(d) < abs(arr[q_min[0]] - arr[i]):
a = q_min[0]
b = i
d = arr[b] - arr[a]
#check if current maximum makes up for the maximum difference so far
if abs(d) < abs(arr[q_max[0]] - arr[i]):
a = q_max[0]
b = i
d = arr[b] - arr[a]
return d, a, b
基本思想是实现上面提到的dynamic algorithm并通过搜索结束于i
的窗口中的最小值和最大值来扩展它。可以找到用于查找阵列的所有窗口的最小值的算法的更详细说明here(或here),尽管这个算法经过微小修改以符合不同的要求,例如滑动 - start-index低于0的窗口以及删除队列中最后一个元素的可能性,因为下一个最大值将是相同的元素。
作为参考(以及使上述算法更容易理解),继承算法列出以i
结尾的窗口的数组的所有最小值:
def min_sliding(arr, w):
q = collections.deque()
for i in range(len(arr)):
while q and q[0] <= i - w:
q.popleft()
while q and arr[i] <= arr[q[-1]]:
q.pop()
q.append(i)
yield q[0]