239. 滑动窗口最大值

坚持第22天,加油!!!

题目

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 1:

输入: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
示例 2:

输入:nums = [1], k = 1
输出:[1]
示例 3:

输入:nums = [1,-1], k = 1
输出:[1,-1]
示例 4:

输入:nums = [9,11], k = 2
输出:[11]
示例 5:

输入:nums = [4,-2], k = 2
输出:[4]
 

提示:

1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length

代码

最开始并不觉得难,觉得用队列就行了,但是运行超时,因为在窗口中选最大值我选的方法不当(遍历比较),后来又改了一下,结果直接结果错了。(代码为反面案例)

class Solution {
    public int midmax=Integer.MIN_VALUE;
    public int[] maxSlidingWindow(int[] nums, int k) {
        //Queue<Integer> queue = new LinkedList<Integer>();
        Deque<Integer> deque = new LinkedList<Integer>();
        List<Integer> list=new ArrayList<Integer>();
        int count=0;
        int max;       
        for(int i=0;i<nums.length;i++)
        {
            if(count<k)
            {
                deque.offerLast(nums[i]);
                count++;
                System.out.println("count"+count+" "+deque);
                if(count==k)
                {
                    max=maxq(deque,midmax);
                    System.out.println(" "+deque+"max"+max+"midmax"+midmax);
                    list.add(max);
                    deque.pollFirst();
                    count--;
                }
               
            }
        }
        return list.stream().mapToInt(Integer::valueOf).toArray();
       

    }
     int maxq(Deque<Integer> deque,int number)
        {
            int max=Integer.MIN_VALUE;
            if(number==Integer.MIN_VALUE)
            {
                int newd=deque.removeFirst();
                System.out.println(deque);
                for(Integer num:deque)
                {
                     midmax=Math.max(midmax,num);
                    // System.out.println("midmax"+midmax+"num"+num);
                }               
                max=Math.max(midmax,newd);
                System.out.println("midmax"+midmax+"max"+max);
                deque.addFirst(newd);
            }else{
                midmax=number;.offerLast
                max=Math.max(deque.peekLast(),number);
            }
            return max;

        }
}

反思

1、队列中的双端队列的使用

2、好的思路:(以后注意选择最值,考虑优先队列(堆)、单调队列、栈)

1)优先队列(堆)

优先队列需要自定义排序方法,注意队列中存的是数组(nums[i],i)。优先队列自己在push,pop都会进行堆的重构。因此peek()就是堆的最值。过程就是将新的元素入堆push,然后判断peek对应的序号是不是在窗口内,若在则peek()就是最值,若不是则pop出,直至出现在窗口内的最值。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>(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) {
            pq.offer(new int[]{nums[i], i});
        }
        int[] ans = new int[n - k + 1];
        ans[0] = pq.peek()[0];
        for (int i = k; i < n; ++i) {
            pq.offer(new int[]{nums[i], i});
            while (pq.peek()[1] <= i - k) {
                pq.poll();
            }
            ans[i - k + 1] = pq.peek()[0];
        }
        return ans;
    }
}

2)单调队列,单调队列在push的操作和一般队列不一样,从而保证了单调性。单调队列还有max()方法返回最值也是peek(),其pop方法和一般的队列也不一样。

class Solution {
    private class MonotonicQueue{
        
        Deque<Integer> deque;

        public MonotonicQueue(){
           deque=new ArrayDeque<Integer>();
        }

        public Integer max(){
            return deque.peekFirst();
        }

        public void pop(int num){
            if(!deque.isEmpty() && num==deque.peekFirst())
                deque.pollFirst();
        }

        public void push(int num){
            while(!deque.isEmpty() && deque.peekLast()<num){
                deque.pollLast();
            }
            deque.addLast(num);
        }

    }

    public int[] maxSlidingWindow(int[] nums, int k) {
        MonotonicQueue windows = new MonotonicQueue();
        ArrayList<Integer> res = new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            if(i < k - 1){
                windows.push(nums[i]);
            }else{
                windows.push(nums[i]);
                res.add(windows.max());
                windows.pop(nums[i-k+1]);
            } 
        }
        return res.stream().mapToInt(Integer::valueOf).toArray();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值