时间窗口内数组的最大绝对差异

时间:2017-05-06 20:45:48

标签: python arrays algorithm

给定一个数组,我想计算给定时间窗口内值的最大绝对差值。

例如,如果数组是股票价格列表,那么这个问题可以被认为是“在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问题有一些相似之处,但有一些重要的区别。首先,是时间窗口的介绍。其次,我正在寻找最大的绝对差异,这对应于最大的利润或亏损,而不是最大的利润。

我尝试过蛮力解决方案,但现在正试图确定一种更有效的方法。是否有针对此问题的已知动态编程解决方案?

1 个答案:

答案 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]