Sliding windows really work here, preserving two stacks (maybe this is a bit misleading, as this is probably best implemented as a double queue). Store the minstack
stack and the stack called maxstack
. The essence of the algorithm is that minstack should be strictly non-decreasing , and maxstack should not strictly increase at all points of the slide. So how do we do this?
First add the first 14 points to the stack. Define add(point)
as:
Do this for minstack:
- While the dot is smaller than the top minstack element, remove the top minstack element.
- Add a point to minstack.
Similarly, for maxstack:
- While the new dot is larger than the top maxstack element, remove the top maxstack element.
- Add a point to maxstack.
Due to the property above, the min and max of the first 14 elements must be the lower elements of minstack and maxstack. Now slide the window. We just have to note that if the left point is still “alive” in any of the stacks, it must be the bottom point. Therefore, it should be easy, simple:
slide(): add(new_point) if (left_point == bottom(minstack)) remove_bottom(minstack) if (left_point == bottom(maxstack)) remove_bottom(maxstack)
Do this until your points are exhausted. The interval you are looking for is the one in which bottom(maxstack) - bottom(minstack)
was the largest.
Please note that any point enters minstack / maxstack no more than once, and each point also leaves stacks no more than once, therefore for each point no more than 4 operations, regardless of the size of the required interval.
EDIT: I just noticed that you want to implement in Python. I really did not want to analyze the data, so the function takes a list of values as input and displays the indices (s, e) in this array:
import collections def add(x, minstack, maxstack): while minstack and x < minstack[-1]: minstack.pop() while maxstack and x > maxstack[-1]: maxstack.pop() minstack.append(x) maxstack.append(x) def get_largest_interval(points): minstack = collections.deque() maxstack = collections.deque() best_diff = -1 best_interval = None for index, elem in enumerate(points): add(elem,minstack,maxstack) if index >= 14: if minstack[0] == points[index-14]: minstack.popleft() if maxstack[0] == points[index-14]: maxstack.popleft() if index >= 13: this_diff = maxstack[0]-minstack[0] if best_diff == -1 or this_diff >= best_diff: best_interval = (index-13, index) best_diff = this_diff return best_interval print get_largest_interval([0, 2, 2,2,2,2,2,2,2,2,2,2,2,2,3])