算法之单调队列

单调队列主要用于降低时间复杂度,使得在O(1)的时间内可以得到栈内最大/小值。
单调队列,顾名思义,就是一个单调递减/递增的队列
力扣上的对应题目有剑指Offer 30. 包含 min 函数的栈,剑指 Offer 59 - I. 滑动窗口的最大值,队列的最大值
以滑动窗口的最大值为例

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 

  滑动窗口的位置                最大值
---------------               -----
[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

首先本题可以使用暴力法来解决,时间复杂度约为O(nk)
为了使时间复杂度降为O(1),可以构建一个单调队列作为辅助

  1. 使用双指针来模拟滑动窗口(注意这个滑动窗口并不是固定不变的大小,也可以变大或变小,因此可以模拟很多情况,应用到其他题目)
  2. 构建一个单调队列用来存储当前的窗口的最大值,保持队列一直都是单调递减的,这样每次取最大值就是取队列第一个,时间复杂度为O(1).
  3. 维护单调队列,就需要在插入和删除元素(窗口滑动)时,做一些改变。

插入(窗口滑动新增的数)如果单调队列中没有元素,则该元素就是最大的,向单调队列中插入该元素
如果单调队列中有元素,则弹出所有比它小的元素再将其入队尾

删除(窗口滑掉的数)如果删掉的数和单调队列中第一个元素相同,则同时弹出单调队列第一个元素

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 0 || k == 0) return new int[0];
        Deque<Integer> deque = new LinkedList<>();
        int[] res = new int[nums.length - k + 1];
        // 未形成窗口
        for(int i = 0; i < k; i++) {
            while(!deque.isEmpty() && deque.peekLast() < nums[i])
                deque.removeLast();
            deque.addLast(nums[i]);
        }
        res[0] = deque.peekFirst();
        // 形成窗口后
        for(int i = k; i < nums.length; i++) {
            if(deque.peekFirst() == nums[i - k])
                deque.removeFirst();
            while(!deque.isEmpty() && deque.peekLast() < nums[i])
                deque.removeLast();
            deque.addLast(nums[i]);
            res[i - k + 1] = deque.peekFirst();
        }
        return res;
    }
}

注意在队列的最大值那里,判断两个list取出的元素是否相同时,一定要进行类型转换,两个Integer对象无法直接用==判断是否相等

list.getFirst()==(int)tmp.getFirst()

你可能感兴趣的:(leetcode,算法,leetcode,职场和发展)