239. Sliding Window Maximum

239. Sliding Window Maximum_第1张图片

最先想到的办法是每个窗中都求最大值,唯一的技巧是保存上一个最大值的位置pos,如果pos出了窗,则遍历当前窗求最值,否则,只需比较窗右边的值和最大值即可。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        
    if (nums.length == 0 || nums == null || k == 0) return new int[]{};

        int[] res = new int[nums.length - k + 1];
        int max_pos = -1;
        int max = Integer.MIN_VALUE;

        for (int i = 0, j = k-1; j < nums.length; j++, i++) {

            if (i > max_pos) { // 左指针已经越过最大值的位置, 则重新在窗口中找最大值
                max = Integer.MIN_VALUE;
                for (int n = i; n < =j; n++) {
                    if (max < nums[n]) {
                        max = nums[n];
                        max_pos = n;
                    }

                }

            } else {
                if (max < nums[j]) {
                    max = nums[j];
                    max_pos = j;
                }

            }

            res[i] = max;
        }

        return res;
    }
}

 此方法平平无奇,居然也可以beat 98%,我也是醉了。

另一种好的方法是采用一个双队列的数据结构,队列保存元素索引。首先判断队列的尾部是否在当前窗内(尾部存放最先入队的元素),不在的话将其去掉,然后比较头部和当前元素nums[i]的大小,如果头部

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {		
		if (nums == null || k <= 0) {
			return new int[0];
		}
		int n = nums.length;
		int[] r = new int[n-k+1];
		int ri = 0;
		// store index
		Deque q = new ArrayDeque<>();
		for (int i = 0; i < nums.length; i++) {
			// remove numbers out of range k
			if (!q.isEmpty() && q.peekLast() < i - k + 1) {
				q.pollLast();
			}
			// remove smaller numbers in k range as they are useless
			while (!q.isEmpty() && nums[q.peekFirst()] < a[i]) {
				q.pollFirst();
			}
			// q contains index... r contains content
			q.offerFirst(i);

			if (i >= k - 1) {
				r[ri++] = nums[q.peekLast()];
			}
		}
		return r;
	}
}

不难看出,队列中保存的都是当前窗口中的元素,准确地说,是当前窗口中从最大值处到right处呈降序排列的元素(如[2,3,8,4,5,3]变成[8,5,3]),所以尾部元素为这些元素的最大值,应放入re中。i增加1,首先要判断边界(队列是否在窗内),然后与nums[i]比较(如果头部的元素小于nums[i],说明头部元素肯定不是窗内最大的元素,所以要把它去掉)。队列记录索引,便于判断边界。

有个python版的,感觉写得不错。

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        
        ans = []
        queue = []                           # queue存放大数的位置
        for i, v in enumerate(nums):         # for i,v 就相当于一趟循环搞定了。
            if queue and queue[0] <= i - k:  # queue里面是index,i-k is gap! j <= i-k => i-j >= k。说明该弹出去了
                queue = queue[1:]            # 弹出最老的pos,queue现在只有后面的值index
            while queue and nums[queue[-1]] < v:  # queue还有值,里面的值都< v, 说明queue里面都不是大值,v最大。
                queue.pop()                  # queue清空 一直到queue空或者当前位置的数大于v才停止循环
            queue.append(i)                  # 循环完毕,现在保存i位置上的大数v,存进quue里面v的位置i
            if i >= k - 1:                   # 如果新加的这个i位置比k大。说明可以加入ans了。取值,加入ans。
                ans.append(nums[queue[0]])   # 事实上,此时queue中的第一个数要大于当前v,v是第二大,但是第一个数给了ans之后
        return ans                           # 再回到loop里面,就又被弹出了,因此原来是第二大的v现在变成了最大!看下面解释。
        
"""
c++版本完全一致,适合背诵!!经典题目啊!
class Solution {
public:
    vector maxSlidingWindow(vector& nums, int k) {
        deque dq;
        vector ans;
        for (int i=0; i=k-1) ans.push_back(nums[dq.front()]);
        }
        return ans;
    }
};
Keep indexes of good candidates in deque d. The indexes in d are from the current window, they're increasing, and their corresponding nums are decreasing. Then the first deque element is the index of the largest window value.
这段话终于看明白了,deque里面的特点是index递增,但是对应值递减,这样满足了k之后,就把第一个给ans。
For each index i:

Pop (from the end) indexes of smaller elements (they'll be useless).
Append the current index.
Pop (from the front) the index i - k, if it's still in the deque (it falls out of the window).
If our window has reached size k, append the current window maximum to the output.
"""
        
        # enumerate(nums) will return index and value
        # if queue is true and queue[0] <= i - k => k <= i - queue[0]
        
"""
>>> a = Solution()
>>> nums, k = [1,3,-1,-3,5,3,6,7], 3
>>> print a.maxSlidingWindow(nums, k)
[3, 3, 5, 5, 6, 7]
"""
import collections

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        d = collections.deque()
        for i in range(len(nums)):
            while d and d[-1] < nums[i]:
                d.pop()
            d.append(nums[i])
            if i > k - 1 and d[0] == nums[i - k]:
                d.popleft()
            if i >= k - 1:
                res.append(d[0])
                
        return res

 

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        
        int[] ans = new int[nums.length - k + 1];
        if (nums.length == 0) return new int[0];
        int[] leftmax = new int[nums.length];
        int[] rightmax = new int[nums.length];
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i ++){
            if (i % k == 0) max = Integer.MIN_VALUE;
            max = Math.max(max, nums[i]);
            leftmax[i] = max;
            
            
        }
        max = Integer.MIN_VALUE;
        for (int i = nums.length-1; i >= 0; i--){
            max = Math.max(max, nums[i]);
            rightmax[i] = max;
            if (i % k == 0) max = Integer.MIN_VALUE;
            
        }
        for (int i = 0; i < nums.length - k + 1; i++){
            ans[i] = Math.max(leftmax[i+k-1], rightmax[i]);
        }
        return ans;
    }
}

 

你可能感兴趣的:(数组与链表)