209. 长度最小的子数组 滑动窗口+暴力

209. 长度最小的子数组

滑动窗口

思路
初始化滑动窗口的起始位置 left = 0、终止位置 right = 0。
外循环先确定滑动窗口的终止位置(增大滑动窗口),找到符合条件的子序列,
根据当前子序列元素和大小的情况,在内循环中移动滑动窗口的起始位置(缩小滑动窗口),找到长度更小的且符合条件的子序列。从而将O(n^2)降为O(n)。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int res = Integer.MAX_VALUE;
        int sum = 0;
        for (int right = 0; right < nums.length; right++) { // 外循环先确定滑动窗口的终止位置
            sum += nums[right];
            while (sum >= target) { // 内循环移动滑动窗口的起始位置
                res = Math.min(res, right - left + 1);
                sum -= nums[left];
                left++;
            }
        }

        return res == Integer.MAX_VALUE ? 0 : res;
    }
}

进阶

  • 窗口内是什么?
    满足其和 >= target 最小长度的连续子数组。
    滑动窗口的本质满足了单调性,即左右指针只会往一个方向走,不会回头,数组中几乎每个元素只进入窗口一次、离开窗口一次。
    收缩的本质是去掉不再需要的元素,本题中先固定移动右指针 right,判断条件是否可以收缩左指针 left。
  • 如何移动窗口的起始位置?
    如果窗口的值 >= target ,窗口左边界 left 就需要向前移动了(窗口前移,窗口缩小)。
  • 如何移动窗口的结束位置?
    窗口的终止位置就是遍历数组的指针right,也就是for循环中的索引。如果窗口值 < target ,窗口右边界 right 前移。(窗口前移,窗口扩大)

补充
如果数组中有负数怎么办?
如果有负数,就不能保证:缩小窗口,其中元素和一定减小;扩大窗口,其元素和一定增大。
此时,每次 left 都要缩小到 right,退化为暴力解法。

暴力

思路
双层循环枚举所有子序列。
for循环表示滑动窗口的起始位置left,必定陷入暴力解法,因为当起始位置先固定时,滑动窗口的终止位置必定用一层for循环寻找。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int k = nums.length;
        
        
        int res = 100001; // 最小长度
        int sum = 0;
        for (int i = 0; i < k; i++) {
            sum += nums[i];
        }
        int sum2 = sum;
        for (int left = 0; left < k; left++) {
            int sum3 = sum2;
            for (int right = k - 1; right >= left; right--) {
                // System.out.print(left);
                // System.out.print("--");
                // System.out.print(right);
                // System.out.print("--");
                // System.out.print(sum2);
                if (sum3 >= target && res > (right - left + 1)) {
                    res = right - left + 1;
                }
                if (sum3 < target) {
                    break;
                }
                sum3 = sum3 - nums[right];
                // System.out.print("--");
                // System.out.print(sum3);
                // System.out.print("--");
                // System.out.println(res);
            }
            sum2 = sum2 - nums[left];
        }

        if (res == 100001) return 0;
        return res;
    }
}
posted @ 2025-10-12 23:14  Nickey103  阅读(46)  评论(0)    收藏  举报