Java力扣---滑动窗口(1)

239. 滑动窗口最大值 - 力扣(LeetCode)

分析:

1.滑动窗口是有元素先进先出的特性的所以可以考虑到队列

2.因为前面的元素是要被删除的,如果考虑常规做法,需要不断地重复计算已经计算过的值


知识点:单调队列=双端队列+单调性


为什么要保证单调?

我们现在要求得是窗口内的最大值,也就是说,如果进来了比当前最大值还要大的,那么当前值在后续将不再成为最大值,所以可以把它清除出去,但是如果进来的是比现在的小的,虽然当前不是最大值,但是当窗口划过当前值之后,他就有可能成为最大值了,所以要保留,这就是为什么求滑动窗口最大值的时候要保证递减;同理,求滑动窗口最小值的时候,要保留比当前值大的数,而不用保留比当前值小的数,所以要保证递增


单调性如何确定?(以严格递减为例)

在队列非空,并且排队的元素比现在队列的最后一个元素大的时候

如果这个排队的元素进来,会导致严格递减不成立

所以把最后一个元素删除

但是这并不意味着倒数第二个,第三个元素就比排队的要大,所以在这一步要用到循环

这样才可以保证新元素进来的时候依然是是递减的,这个时候才让新元素进来


为什么要在队列中放序号而不是数值?

因为是窗口,要保证先进先出,如果直接放数值,那么就没有窗口的顺序了-----要保证数据是在窗口内的


新元素进来可能会导致窗口溢出,所以要判断需不需要把最前面的元素删除

在本题中,还要顾及到记录该窗口的最大值

java 复制代码
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;

public class test {
    static void main() {
        int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};
        int k = 1;
        System.out.println(Arrays.toString(maxSlidingWindow(nums, k)));
    }

    public static int[] maxSlidingWindow(int[] nums, int k) {

        Deque<Integer> queue = new ArrayDeque<>();
        int[] arr = new int[nums.length - k + 1];
        //遍历
        for (int i = 0; i < nums.length; i++) {
            //先加新数
            //判queue空不空
            while (!queue.isEmpty() && nums[queue.getLast()] < nums[i]) {
                //如果新来的数更大
                //那么前面的都不再是我后面会用到的最大值
                //把比新来的小的都清除
                queue.removeLast();
            }
            //没满的则要判断是否进队
            //如果新来的数更小
            //那就让他进来,因为可能是后面的数里面的最大值
            queue.addLast(i);

            //判断该不该清除前面的(size够不够)
            int left = i - k + 1;
            if (left > queue.getFirst()) {
                //要把左边的移出去
                queue.removeFirst();
            }
            //记录滑动窗口的最大值
            if (left >= 0) arr[left] = nums[queue.getFirst()];
        }
        return arr;
    }
}

1438. 绝对差不超过限制的最长连续子数组

选择滑动窗口的原因:子数组越长,最大值越大,最小值越小,越不能满足本题的要求,反之,子数组越短,越能满足本题的要求--------满足这样的性质的,可以用滑动窗口


由于要计算的是最大值和最小值之间的差异,所以要记录最大值和最小值两个数值,要定义两个队列,一个用来存放最大值,一个放最小值

但是最大值越大,最小值越小,越容易不满足题目要求-------所以最大值要缩小,最小值要变大--------所以最大值队列要递减,最小值队列要递增

如果最大值和最小值之间的差距过大了,那么就要踢出去他们其中的一个----谁先进来的谁先出去----所以要有一个数值记录窗口的开始在哪里,如果当前超出限制,那么窗口就要滑动,也就是开始值要加一

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;

public class test {
    static void main() {
        int[] nums = {10, 1, 2, 4, 7, 2};
        int k = 5;
        System.out.println(maxSlidingWindow(nums, k));
    }

    public static int maxSlidingWindow(int[] nums, int limit) {
        Deque<Integer> maxqueue = new ArrayDeque<>();
        Deque<Integer> minqueue = new ArrayDeque<>();

        int left = 0;
        int maxnum = 0;

        for (int i = 0; i < nums.length; i++) {
            //让最大队列递减,让最小队列递增
            while (!maxqueue.isEmpty() && nums[maxqueue.getLast()] < nums[i]) {
                maxqueue.removeLast();
            }
            maxqueue.addLast(i);
            while (!minqueue.isEmpty() && nums[minqueue.getLast()] > nums[i]) {
                minqueue.removeLast();
            }
            minqueue.addLast(i);
            //做判断,如果在大于限制,要右滑窗口,把最前面的窗口移出去
            while (nums[maxqueue.getFirst()] - nums[minqueue.getFirst()] > limit) {
                left++;
                if (maxqueue.getFirst() < left) {
                    maxqueue.removeFirst();
                }
                if (minqueue.getFirst() < left) {
                    minqueue.removeFirst();
                }
            }
            maxnum = Math.max(maxnum, i - left + 1);
        }
        return maxnum;
    }
}

学习思路来自灵茶山艾府 - 力扣(LeetCode)

相关推荐
一水鉴天6 小时前
整体设计 之28 整体设计 架构表表述总表的 完整程序(之27 的Q268 )(codebuddy)
java·前端·javascript
net3m336 小时前
雅特力单片机用串口USART_INT_TDE中断比用USART_INT_TRAC的 发送效率要高
java·开发语言·算法
雪碧聊技术6 小时前
深入解析:Java中int类型转换为String类型的多种方法
java·整数转为字符串
BD_Marathon6 小时前
【JavaWeb】启动tomcat报错:启动子级时出错
java·tomcat
while(1){yan}6 小时前
网络协议TCP
java·网络·网络协议·tcp/ip·青少年编程·电脑常识
一过菜只因6 小时前
JavaWeb后端(spring--boot)
java·开发语言
@我漫长的孤独流浪6 小时前
程序综合实践第十二周-二叉树
算法·深度优先·图论
啊阿狸不会拉杆6 小时前
《数字图像处理》第 3 章 - 灰度变换与空间滤波
图像处理·人工智能·算法·计算机视觉·数字图像处理