LeetCode 239.滑动窗口的最大值

leetcode239.滑动窗口的最大值

原题目

在这里插入图片描述

思路

思路一:

自己刚刚写的时候,是用优先队列写的,每次从队列中取出的都是当前队列中的最大值,加到结果中去。代码如下:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length==0)
            return new int[0];
        Comparator<Integer> cmp = (e1,e2)->{
            return e2-e1;
        };
        Queue<Integer> q1 = new PriorityQueue<Integer>(cmp);
        int[] ans = new int[nums.length-k+1];
        for(int i = 0;i<k;i++){
            q1.add(nums[i]);
        }
        ans[0] =q1.peek();
        for(int i = 1;i<nums.length-k+1;i++){
            q1.remove(nums[i-1]);
            q1.add(nums[k+i-1]);
            ans[i] = q1.peek();
        } 
        return ans;
    }
}

思路二

用双向队列解决,思路是这样的队列中保存的是数组中的下标,有序,每次添加元素时都需要判断结尾中的下标所对应的值是否大于此数所对应的值,不是的话,直接加到队列中,否则删除队尾中的数,直到此数在正确的位置上即可。
代码如下:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
           int len = nums.length;
           if(len==0)
                return new int[0];
           ArrayDeque<Integer> arr = new ArrayDeque<>();
           int max_id = 0;
           int[] ans = new int[len-k+1];
           for(int i = 0;i<k;i++){
               while(!arr.isEmpty()&&nums[i]>nums[arr.getLast()]){
                   arr.removeLast();
               }
               arr.add(i);
           }
           ans[0] = nums[arr.getFirst()];
           for(int i = k;i<len;i++){
           		//因为队列中的数代表的是下标,所以此处if判断的是是否将下标移除
               if(!arr.isEmpty()&&arr.getFirst()<=i-k)
                    arr.removeFirst();
                while(!arr.isEmpty()&&nums[i]>nums[arr.getLast()]){
                   arr.removeLast();
               }
               arr.add(i);
               ans[i-k+1] = nums[arr.getFirst()];
           }
           return ans;
    }
}

思路三

动态规划,真的厉害,完全想不到竟然还可以用动态规划进行解决(Orz)
声明一下图片来自leetcode中
首先将数组分块,即len%k
来自leetcode中
用left数组代表从块的左边到右边的最大值
right数组代表从块的右边到左边的最大值
在这里插入图片描述
解释input被分为3个部分 即[1,3,-1],[-3,5,3],[6,7];
left当访问块的开始时,直接等于即可,即当访问1时,最大即left[0]=1;
访问3时,因为比1大,所以left[1]=3,
访问-1时,因为比3小,所以left[2]=3,
访问-3时,因为为块的开始,即left[3] = -3,以此类推
而right数组则从最后一块开始,从右侧开始到左侧结束就好,以此递推就出来了
那么怎么得出结果ans数组呢?ans[i] = max(right[i],left[i+k-1])
假如正是[-1,-3,5]这三个数
当处于上面的那个状态时,right[i]就代表此时从-1开始到-1结束的最大值,即-1
left[i+k-1]就代表[-3,5]之间的最大值
代码

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
           int len = nums.length;
           if(len==0)
                return new int[0];
            int[] left = new int[len];
            int[] right = new int[len];
            left[0] = nums[0];
            right[len-1] = nums[len-1];
            for(int i = 1;i<len;i++){
                if((i)%k==0){
                    left[i] = nums[i];
                }
                else{
                    left[i] = Math.max(left[i-1],nums[i]);
                }
                int ri_pos = len-i-1;
                if((ri_pos+1)%k==0){
                    right[ri_pos] = nums[ri_pos];
                }
                else{
                    right[ri_pos] = Math.max(right[ri_pos+1],nums[ri_pos]);
                }
            }
            int[] ans = new int[len-k+1];
            for(int i = 0;i<len-k+1;i++){
                ans[i] = Math.max(left[i+k-1],right[i]);
            }
            return ans;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值