算法-滑动窗口-Java

本文介绍了使用Java实现滑动窗口算法,特别是如何利用双端队列高效地找到窗口内的最大值和最小值,以及应用该算法解决求解数组中最大值与最小值之差小于或等于num的子数组数量问题。分析了双端队列在处理滑动窗口问题中的作用,并提供了O(N)时间复杂度的解决方案。
摘要由CSDN通过智能技术生成

滑动窗口-Java

  • 生成窗口的最大值或者最小值数组,时间复杂度:O(N)。

  • 普通解法的时间复杂度为O(N * win),也就是每次对一个窗口遍历其中的 win 个数,选出最大值,最优解可以做到 O(N)。

  • 【分析】:**准备一个双端队列,双端队列存放着数组中的下标值。**假设当前为 arr[i],则放入规则如下:

  • left 和 right 指针都只会向右移动,不会回退。

  • right 右滑,窗口加数:

    • 1)如果 queue 为空,直接把下标 i 放入 queue 中;
    • 2)如果 queue 不为空,取出当前 queue 队尾存放的下标 j。如果 arr[j] > arr[i],则直接把 i 放入队尾;
    • 3)如果 arr[j] <= arr[i],则一直从 queue 的队尾弹出下标,直到某个下标在 queue 中的对应值大于 arr[i],然后把 i 放入队尾 【为什么可以弹出,因为我永远比你晚过期,我又比你大或者和你一样大,有我在,你永远不可能最大,所以你可以滚了】
  • left 右滑,窗口减数:

    • 1)看弹出的 left 是否与队列头相等,如果相等,说明这个队列头已经不在窗口内了,所以弹出 queue 当前的队首元素 。
  • 双端队列的队头就是当前窗口最大值的下标。

public class Window {
   
    public int[] arr;
    private int left;
    private int right;
    private final LinkedList<Integer> queue;
    public Window(int[] arr){
   
        this.arr = arr;
        left = 0;
        right = 0;
        queue = new LinkedList<>();
    }

    public Integer getMax(){
   
        if (queue.isEmpty()){
   
            return null;
        }
        return arr[queue.peekFirst()];
    }

    // 往滑动窗口加数时对双端队列的操作
    public void addNumToRight(){
   
        if (right == arr.length){
   
            // right已经到达最右了,滑动窗口无法再增加数了
            return;
        }

        while (!queue.isEmpty() && arr[queue.peekLast()] <= arr[right]){
   
            queue.pollLast();
        }

        queue.add(right);
        right++;
    }

    // 移除双端队列最左边的值
    public void remo
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
滑动窗口算法(Sliding Window Algorithm)是一种常用的算法技巧,用于解决一些数组或字符串相关的问题。它通过维护一个固定大小的窗口,并在窗口滑动的过程中对窗口中的元素进行处理,从而得到问题的解。 下面是一个使用滑动窗口算法解决问题的示例,使用Java语言实现: ```java public class SlidingWindowAlgorithm { public static void main(String[] args) { int[] nums = {2, 4, 1, 5, 3, 2, 7, 1}; int targetSum = 8; int result = findTargetSum(nums, targetSum); System.out.println("Result: " + result); } public static int findTargetSum(int[] nums, int targetSum) { int windowSum = 0; // 窗口内的元素和 int windowStart = 0; // 窗口的起始位置 int minLength = Integer.MAX_VALUE; // 记录最小子数组长度 for (int windowEnd = 0; windowEnd < nums.length; windowEnd++) { // 窗口右移,加上当前元素 windowSum += nums[windowEnd]; // 当窗口内元素和大于等于目标和时,缩小窗口 while (windowSum >= targetSum) { // 更新最小子数组长度 minLength = Math.min(minLength, windowEnd - windowStart + 1); // 窗口左移,减去左边界元素 windowSum -= nums[windowStart]; windowStart++; } } return minLength != Integer.MAX_VALUE ? minLength : 0; } } ``` 以上示例中,我们使用滑动窗口算法来寻找数组中和大于等于目标和的最小子数组长度。通过维护一个窗口,不断向右移动,并根据窗口内元素和与目标和的比较来调整窗口的大小。最后返回最小子数组长度。 希望以上示例能帮助到您理解滑动窗口算法的使用。如果您有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

木子津

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

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

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

打赏作者

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

抵扣说明:

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

余额充值