java数据结构与算法刷题-----LeetCode239. 滑动窗口最大值

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

在这里插入图片描述

1. 法一:指针法

解题思路
  1. 我们以每一个窗口来看,找到每个窗口的最大值
  2. 那么找到最大值后,会面临一些情况。就是窗口滑动后,会从左边少一个元素,右边多一个元素
  3. 首先,如果右边多出来的,比当前最大值大的话,那它一定是新的最大值。因为上一次窗口中最大为max。而新加了一个右边的,比max大,那么右边这个就是最大的
  4. 如果右边的没有当前max大。那么就考虑左边,如果左边少了一个后,新的最左边结点和max一样,那么左边这个就是新最大值
  5. 如果刚好,上一次的max,在滑动窗口后,不在窗口范围了,那么没办法,只能遍历窗口元素,找到新的最大值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
代码:时间复杂度O(n),空间复杂度O(1)

在这里插入图片描述

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int left = 0;//滑动窗口左边界
        int right = k - 1;//滑动从窗口右边界
        int maxIndex = -1;//max元素下标
        int max = Integer.MIN_VALUE;//max - 1 = Integ.MAX_VALUE;

        int[] res = new int[nums.length - k + 1];//结果数组

        while (right < nums.length) {//还可以滑动就继续
            if (maxIndex > left) {//如果max在left右边
                if (nums[right] > max - 1) {//判断是否新添加元素>max
                    maxIndex = right;//如果right新元素>max就让max指向right
                    max = nums[maxIndex];
                }
            } else if (nums[right] > max - 1) {//如果max不在left右边,但是新添加元素,刚好>max
                maxIndex = right;//那么right一定新窗口是最大值,因为max是旧窗口的最大值
                max = nums[maxIndex];
            }else if (nums[left] >= max - 1 ) {//如果max不在left右边,而且right不是最大值,那么看看left是否是最大值
                maxIndex = left;//区域减少了一个值,添加一个right,right不是最大值,那就看看left是不是最大值
                max = nums[left];//是,就让max指向left
            }else {//上面条件都不成立,最大值既不是right也不是left,而是在中间的话。就只能循环找了
                maxIndex = left;
                max = nums[maxIndex];
                for (int i = left + 1; i <= right; i++) {
                    if (nums[i] > max - 1) {
                        maxIndex = i;
                        max = nums[maxIndex];
                    }
                }
            }
            res[left] = max;//每次都保存最大值
            left++;//滑动窗格
            right++;//滑动窗格
        }
        return res;
    }
}

2. 法二:单调队列

解题思路
  1. 每一个元素的下标都会从右端插入队列
  2. 如果插入时,队列前面的元素小于当前插入元素。说明它们不会是当前窗口最大值,我们将前面比它小的取出。然后插入当前元素
  3. 因为每次我们都将前面较小的去除了,所以最左边的元素永远是当前最大的。
  4. 但是最左边的这个下标,如果不是当前窗口范围内的下标,就先去除。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
代码:时间复杂度O(n),空间复杂度O(n)

在这里插入图片描述

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        Deque<Integer> deque = new LinkedList<Integer>();//单调队列保存下标 first <--|  队列  |--> last
        //处理第一个窗口
        for (int i = 0; i < k; ++i) {//将k个元素的下标放入单调队列
            //如果队列不为空,新元素比前面的元素大,就将前面比它小的元素取出
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();//将前面小的取出
            }
            deque.offerLast(i);//将当前值的下标放入队列,保证它前面都是值比它大的下标
        }
        int[] ans = new int[n - k + 1];//答案数组,需要n-k+1个答案,也就是一共n-k+1个窗口
        ans[0] = nums[deque.peekFirst()];//将刚刚处理的第一个窗口结果放入ans[0]
        //处理剩下的窗口
        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()];//因为我们一直都只保留大的值,所以first就是当前窗口最大值
        }
        return ans;
    }
}
  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值