0
点赞
收藏
分享

微信扫一扫

LeetCode 热题100-69-滑动窗口最大值

猎书客er 2022-05-05 阅读 51

核心思想:优先队列
思路:
建立一个大根堆的优先队列,队头永远是当前最大元素。为了方便记录每个元素在原数组中的位置,我们把优先队列中的元素设置为int数组,int[0]存储数值,int[1]存储位置索引。
首先,把前k个元素的int数组存入队列中;然后创建ans数组,存储每个滑动窗口中最大元素数值,其长度为n-k+1,首先另ans[0]=队头元素;接着,遍历剩余的n-k个元素,每次都会将新的元素加入到优先队列中,同时判断当前优先队列中,有没有元素的位置比j-k小的,小的话就弹出(为什么?因为[0,j-k]是滑动窗口左边的元素集合,而j-k是边界,凡是比这个小的,都是窗口之外的元素)(为什么用while,因为不是每次循环必定弹出队头,所以不用设置成长度为k的优先队列,先存着,如果出现队头在滑动窗口之外,就弹出直至到达滑动窗口内);同时更新每个窗口的最大值在ans[j]中;最后,但会ans数组。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>(){
            public int compare(int[] pair1, int[] pair2){
                return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
            }
        });
        for(int i = 0; i < k; i++){
            queue.offer(new int[]{nums[i], i});
        }
        int[] ans = new int[nums.length - k + 1];
        ans[0] = queue.peek()[0];
        for(int j = k; j < nums.length; j++){
            queue.offer(new int[]{nums[j], j});
            while(queue.peek()[1] <= j - k){
                queue.poll();
            }
            ans[j - k + 1] = queue.peek()[0];
        }
        return ans;
    }
}

下边是最优解,速度最快的方法:
核心思想:单调栈
思路:
维护一个单调递减的栈,当滑动窗口向右移动时,我们需要把一个新的元素放入队列中。为了保持队列的性质(先进先出),我们会不断地将新的元素与队尾的元素相比较,如果前者大于等于后者,那么队尾的元素就可以被永久地移除,我们将其弹出队列。我们需要不断地进行此项操作,直到队列为空或者新的元素小于队尾的元素。
由于队列中下标对应的元素是严格单调递减的,因此此时队首下标对应的元素就是滑动窗口中的最大值。但与上述方法相同的是,此时的最大值可能在滑动窗口左边界的左侧,并且随着窗口向右移动,它永远不可能出现在滑动窗口中了。因此我们还需要从队首弹出元素,直到队首元素在窗口中为止。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> deque = new LinkedList<>();
        for(int i = 0; i < k; i++){
            while(!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]){
                deque.pollLast();
            }
            deque.offerLast(i);
        }
        int[] ans = new int[nums.length - k + 1];
        ans[0] = nums[deque.peekFirst()];
        for(int j = k; j < nums.length; j++){
            while(!deque.isEmpty() && nums[j] > nums[deque.peekLast()]){
                deque.pollLast();
            }
            deque.offerLast(j);
            //添加一个元素,可能队列长度长度超出k
            if(deque.peekFirst() <= j - k){
                deque.pollFirst();
            }
            ans[j - k + 1] = nums[deque.peekFirst()];
        }
        return ans;
    }
}

这个方法与上面把那个方法最大的不同就是:下边的方法可以保证队头元素一定是最远元素;而且下边的方法队列最长为k+1.

举报

相关推荐

0 条评论