LeetCode 239 Sliding Window Maximum

446 阅读2分钟

LeetCode 239 Sliding Window Maximum

链接:leetcode.com/problems/sl…

方法:双端队列

时间复杂度:O(n)

空间复杂度:O(n)

想法:这个题从一开始想的话确实比较难,但我之前已经在LeetCode 1438的题解里写过这种方法了,所以这样倒着复习的话这道题就非常简单了。就是一个双端队列实现动态维护最值,放元素的时候从Last那头放,取最值从First那头取。比方说这道题让我们求滑动窗口的最大值,那肯定得用一个维护最大值的双端队列,那么这个队列从First到Last这个方向一定是单调递减或单调不增(看题目具体情况)。对于这一道题目,队列里面放index也可以,放值也可以。

我们首先考虑放进去的是值,比方说我滑动窗口里有三个3,左边界往右挪的时候,要删掉一个值,万一是3,那么删掉它,我们需要保证队列里面还有两个3,那就是说这种情况我们要维护一个单调不增的序列即可,遇上左边界的值等于队列最值的时候直接大胆删。

如果放进去index可以做吗?这题也可以,因为我如果放index的话,左边界挪的时候,直接检查左边界是不是队列First那端的值就可以了,所以如果用index,这里就既可以用单调递减,也可以单调不增。下面代码只放一个放值的做法,但是改成放index完全没有难度。

代码:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        Deque<Integer> maxQ = new ArrayDeque<>();
        
        int i = 0;
        for (; i < k - 1; i++) {
            while (!maxQ.isEmpty() && maxQ.peekLast() < nums[i]) {
                maxQ.pollLast();
            }
            maxQ.addLast(nums[i]);
        }
        
        int[] res = new int[n - k + 1];
        for (; i < n; i++) {
            while (!maxQ.isEmpty() && maxQ.peekLast() < nums[i]) {
                maxQ.pollLast();
            }
            maxQ.addLast(nums[i]);
            
            res[i - k + 1] = maxQ.peekFirst();
            
            if (maxQ.peekFirst() == nums[i - k + 1]) {
                maxQ.pollFirst();
            }
        }
        
        return res;
    }
}