PU Sliding Window Maximum

Jan 01, 1970

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

  • You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.
  • Could you solve it in linear time?

For example,

  • Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
  • Therefore, return the max sliding window as [3,3,5,5,6,7].

C Solution 1:

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 */
void push(int *heap, int *top, int val) {
    heap[(*top)++] = val;
    int cur = *top - 1, root = cur / 2;
    while (root && heap[cur] > heap[root]) {
        int tmp = heap[cur];
        heap[cur] = heap[root];
        heap[root] = tmp;
        cur = root;
        root = cur / 2;
    }
}
int pop(int *heap, int *top) {
    int res = heap[1];
    heap[1] = heap[--*top];
    int root = 1, left = 2;
    while (left < *top) {
        if (left + 1 < *top && heap[left + 1] > heap[left]) left++;
        if (heap[root] >= heap[left]) return res;
        int tmp = heap[root];
        heap[root] = heap[left];
        heap[left] = tmp;
        root = left;
        left = 2 * root;
    }
    return res;
}
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
    if (!nums || !numsSize) return 0;
    *returnSize = 0;
    int *res = malloc((numsSize - k + 1) * sizeof(int));

    int *all = malloc((numsSize + 1) * sizeof(int)), topa = 1;
    int *done = malloc((numsSize + 1) * sizeof(int)), topd = 1;

    int i;
    for (i = 0; i < k; i++) push(all, &topa, nums[i]);
    res[(*returnSize)++] = all[1];
    for (; i < numsSize; i++) {
        push(all, &topa, nums[i]);
        push(done, &topd, nums[i - k]);
        while (topd > 1 && all[1] == done[1]) {
            pop(all, &topa);
            pop(done, &topd);
        }
        res[(*returnSize)++] = all[1];
    }
    return res;
}

C Solution 2:

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 */
#define MAX(x, y) ((x) > (y) ? (x) : (y))
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
    if (!nums || !numsSize) return 0;
    int *toleft = malloc(numsSize * sizeof(int));
    int *toright = malloc(numsSize * sizeof(int));
    toleft[0] = nums[0];
    toright[numsSize - 1] = nums[numsSize - 1];
    int i;
    for (i = 1; i < numsSize; i++) {
        toleft[i] = i % k == 0 ? nums[i] : MAX(toleft[i - 1], nums[i]);
        int j = numsSize - 1 - i;
        toright[j] = j % k == 0 ? nums[j] : MAX(toright[j + 1], nums[j]);
    }
    *returnSize = 0;
    int *res = malloc((numsSize - k + 1) * sizeof(int));
    for (i = 0; i < numsSize - k + 1; i++) {
        res[(*returnSize)++] = MAX(toright[i], toleft[i + k - 1]);
    }
    return res;
}

Python Solution 1:

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not nums: return []
        res = []
        heap = []
        for i in range(k):
            heapq.heappush(heap, -nums[i])
        res.append(-heap[0])
        discards = collections.defaultdict(int)
        for i in range(k, len(nums)):
            discards[-nums[i - k]] += 1
            heapq.heappush(heap, -nums[i])
            while discards[heap[0]] > 0:
                discards[heap[0]] -= 1
                heapq.heappop(heap)
            res.append(-heap[0])
        return res

Python Solution 2:

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not k or not nums: return []
        l = nums[:]
        r = nums[::-1]
        for i, num in enumerate(l):
            if i % k:
                l[i] = max(l[i - 1], num)
        last = len(nums) % k
        for i in range(1, last):
            r[i] = max(r[i - 1], r[i])
        for i in range(last, len(nums)):
            if i % k != last:
                r[i] = max(r[i - 1], r[i])
        r = r[::-1]
        print(l, r)
        res = []
        for i in range(len(nums) - k + 1):
            res.append(max(r[i], l[i + k - 1]))
        return res

Python Solution 3:

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not nums or not k: return []
        l = nums[:]
        r = nums[:]
        for i in range(1, len(nums)):
            if i % k:
                l[i] = max(l[i - 1], l[i])
            j = len(nums) - 1 - i
            if j % k:
                r[j] = max(r[j + 1], r[j])
        return [max(r[i], l[i + k - 1]) for i in range(len(nums) - k + 1)]

Python Solution 4:

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not nums: return []
        heap = [(-num, i) for i, num in enumerate(nums[:k])]
        heapq.heapify(heap)
        res = []
        res.append(-heap[0][0])
        for i in range(k, len(nums)):
            heapq.heappush(heap, (-nums[i], i))
            while heap[0][1] <= i - k:
                heapq.heappop(heap)
            res.append(-heap[0][0])
        return res

Summary:

  1. The key point is to use heap to track the maximum val.
  2. But deletion is not O(lg(N)) in heap, so I have to use another heap to check record all the deleted val.
    • If the max of both heap is equal, that means this maximum val is not valid. delete and try again.
  3. The first: 36ms, 80.95%. The second: 32ms, 100%.
  4. The O(1) solution is smart and can be reused in many sliding-window problem, I think.

LeetCode: 239. Sliding Window Maximum