算法之滑动窗口

力扣239

package com.zhang.reflection.面试.算法模版.滑动窗口;
import java.util.Deque;
import java.util.LinkedList;
import java.util.PriorityQueue;
/**
 * 给你一个整数数组 nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。
 * 你只可以看到在滑动窗口内的 k个数字。滑动窗口每次只向右移动一位。
 *
 * 返回 滑动窗口中的最大值 。
 *
 */
public class 滑动窗口最大值 {
    /**
     * 解法一:使用优先队列
     * 对于「最大值」,我们可以想到一种非常合适的数据结构,那就是优先队列(堆),其中的大根堆可以帮助我们实时维护一系列元素中的最大值。
     *
     * 对于本题而言,初始时,我们将数组 \textit{nums}nums 的前 kk 个元素放入优先队列中。
     * 每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,
     * 在这种情况下,这个值在数组 \textit{nums}nums 中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,
     * 这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除。
     *
     * 我们不断地移除堆顶的元素,直到其确实出现在滑动窗口中。此时,堆顶元素就是滑动窗口中的最大值。
     * 为了方便判断堆顶元素与滑动窗口的位置关系,我们可以在优先队列中存储二元组 (\textit{num}, \textit{index})(num,index),
     * 表示元素 \textit{num}num 在数组中的下标为 \textit{index}index。
     */
    public int[] maxSlidingWindow(int[] nums, int k) {
        PriorityQueue<int[]> heap=new PriorityQueue<int[]>((a, b)->a[0]==b[0]?b[1]-a[1]:b[0]-a[0]);
        for(int i=0;i<k;i++){
            heap.offer(new int[]{nums[i],i});
        }
        int[] result=new int[nums.length-k+1];
        result[0]=heap.peek()[0];
        for(int i=k;i<nums.length;i++){
            heap.offer(new int[]{nums[i],i});
            while(heap.peek()[1]<=i-k){
                heap.poll();
            }
            result[i-k+1]=heap.peek()[0];
        }
        return result;
    }

    /**
     * 解法二:单调队列
     * https://leetcode-cn.com/problems/sliding-window-maximum/solution/hua-dong-chuang-kou-zui-da-zhi-by-leetco-ki6m/
     */
    public int[] maxSlidingWindow1(int[] nums, int k) {
        int n = nums.length;
        Deque<Integer> deque = new LinkedList<Integer>();
        for (int i = 0; i < k; ++i) {
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();
            }
            deque.offerLast(i);
        }

        int[] ans = new int[n - k + 1];
        ans[0] = nums[deque.peekFirst()];
        for (int i = k; i < n; ++i) {
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();
            }
            deque.offerLast(i);
            while (deque.peekFirst() <= i - k) {
                deque.pollFirst();
            }
            ans[i - k + 1] = nums[deque.peekFirst()];
        }
        return ans;
    }
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-02 14:45
bg是二本双一流硕,目标是Java后端开发岗,投暑期实习0大厂面试,只有极少的大厂测开,可能投的晚加上简历太烂加上0实习?求大佬们给个建议
程序员小白条:别去小厂,初创或者外包,尽量去中小,100-499和500-999,专门做互联网产品的,有公司自研的平台和封装的工具等等,去学习一些业务相关的,比如抽奖,积分兑换,SSO认证,风控,零售等等,目标 Java 后端开发吗?你要不考虑直接走大厂测开?如果技术不行的话,有面试你也很难过的
实习,不懂就问
点赞 评论 收藏
分享
05-11 20:45
门头沟学院 Java
有担当的灰太狼又在摸...:零帧起手查看图片
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务