optimal way to find sum(S) of all contiguous sub-array's max difference

荒凉一梦 提交于 2019-12-01 01:25:45

Suppose you have a sequence of length n, and you wish to calculate the minimum (or maximum) of a sliding window of some fixed size m < n. Then (surprisingly), this can be done in O(n) time.

So now for window sizes m = 1, ..., n, you need to run the sliding window from left to right; for each slide of the window, you just need to add the max - min of the elements inside the window. By the above, the running time is Theta(n^2). This improves your naive algorithm which is Theta(n^3).

This can be done in linear time! Each element goes into the sum once for every subarray it's the max of, and each element is subtracted once for every subarray it's the minimum of. We need a linear-time algorithm for finding how many subarrays each element is the max or min of, and we can do that with a minor modification of an all nearest smaller values algorithm.

The idea is that to find how many subarrays an element is the max of, we keep a stack of the elements we've seen that are greater than all subsequent elements we've seen, along with the positions of those numbers. When we find an element greater than the last element on the stack, we know how far a subarray can extend to the left or right of the element on the top of the stack and still have it be the maximum, and we can use that to determine how many subarrays it's the max of. We can handle the minimums by simply negating all elements of the array.

def max_sums(d):
    stack = [(-1, float('inf'))]
    sum_ = 0
    for i, x in enumerate(d):
        while x > stack[-1][1]:
            prev_i, prev_x = stack.pop()
            prev_prev_i, prev_prev_x = stack[-1]
            sum_ += prev_x * (i - prev_i) * (prev_i - prev_prev_i)
        stack.append((i, x))
    while len(stack) > 1:
        prev_i, prev_x = stack.pop()
        prev_prev_i, prev_prev_x = stack[-1]
        sum_ += prev_x * (len(d) - prev_i) * (prev_i - prev_prev_i)
    return sum_

def max_differences_sum(d):
    return max_sums(d) + max_sums([-x for x in d])

Here's an example run of the algorithm. Suppose the input is [30, 10, 40, 20]. Then to compute the sum of the maxes of all subarrays, we iterate over the input as follows:

30

We push the pair (0, 30) onto the stack. The stack now records that we saw a 30 at index 0.

10

30 > 10, so we push the pair (1, 10) onto the stack. The stack now records that we saw a 10 at index 1.

40

10 < 40, so a subarray with max 10 cannot include this element. We see that a subarray with max 10 must start after the index of 30 and end before the index of 40, so it has 1 possible left endpoint and 1 possible right endpoint, and there is 1*1 such array. We add 10*1*1 to the sum and pop the (1, 10) from the stack. The sum is now 10.

30 < 40, so a subarray with max 30 also cannot include this element. We see that a subarray with max 30 must start index 0 and end at either index 0 or index 1, so there are 1*2 such arrays. We add 30*1*2 to the sum and pop the (0, 30). The sum is now 70.

The stack is now empty, so we push (2, 40).

20

40 > 20, so we push (3, 20).

We have iterated through all the input, so for any pair (i, x) still on the array, a subarray with max x can end anywhere from index i to the end of the array, and it can start anywhere from i to the previous stack entry's index (or the start of the array if there is no previous entry).

(3, 20) is on the stack with (2, 40) beneath it, so a subarray with max 20 must start and end at index 3. We add 20*1*1 to the sum and pop (3, 20). The sum is now 90.

(2, 40) is on the stack with nothing beneath it, so a subarray with max 40 can start at any index <= 2 and end at any index >= 2. We add 40*3*2 to the sum and empty the stack. The sum is now 330.

We've accounted for all positive terms in the sum. To subtract the minimums, we negate all input elements and feed them through the above algorithm again. We end up subtracting 170, for an overall total of 160.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!