LeetCode 209. 长度最小的子数组

滑动窗口,初始时left和right都指向第一个位置。如果和小,那么right右移。如果和大于等于,满足条件形成了子数组,left右移,缩小左边界,寻找新的结果。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int len=nums.length;
        int left=0,right=0;
        int min=Integer.MAX_VALUE;//记录最小子数组的大小
        int sum=0;
        while(right<len){
            sum+=nums[right];//将数字加入子数组
            //问题求:其总和大于等于 target
            while(sum>=target){//找到一个子数组[left,right]
                min=Math.min(min,right-left+1);
                sum-=nums[left];
                left++;
            }
            //sum<target
            right++;
        }
        return min==Integer.MAX_VALUE?0:min;//无结果,返回0
    }
}

什么时候使用滑动窗口?

维护一个可以滑动的窗口,在数组或字符串等线性数据结构上进行高效的操作。

1. 子数组或子字符串问题

  • 问题特征:当问题要求在一个数组或字符串中找出满足特定条件的连续子数组或子字符串时,滑动窗口往往是一个不错的选择。例如,需要找出和满足一定条件(如和大于等于某个值、和等于某个值)的最短或最长连续子数组,或者找出包含特定字符的最短或最长连续子字符串等。
  • 示例题目
    • 209. 长度最小的子数组:给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的连续子数组。可以使用滑动窗口不断调整窗口的大小和位置,找到满足条件的最小子数组长度。
    • 76. 最小覆盖子串:给定一个字符串 s 和一个字符串 t,在 s 中找到包含 t 中所有字符的最小子串。通过滑动窗口,在 s 上移动窗口,不断调整窗口的左右边界,找到满足条件的最小子串。

2. 固定大小窗口问题

  • 问题特征:问题要求处理固定大小的连续子数组或子字符串。在这种情况下,可以使用一个固定大小的滑动窗口在数据结构上滑动,依次处理每个窗口内的元素。
  • 示例题目
    • 剑指 Offer 57 - II. 和为 s 的连续正数序列:输入一个正整数 target,输出所有和为 target 的连续正整数序列(至少含有两个数)。可以使用一个固定大小的滑动窗口,从较小的窗口开始,逐步调整窗口大小,找到所有满足条件的连续正整数序列。
    • 643. 子数组最大平均数 I:给定一个由 n 个元素组成的整数数组 nums 和一个整数 k,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。使用固定大小为 k 的滑动窗口在数组上滑动,计算每个窗口内元素的和,进而得到最大平均数。

3. 区间统计问题

  • 问题特征:需要统计满足特定条件的区间数量。滑动窗口可以通过动态调整窗口的边界,高效地统计符合条件的区间。
  • 示例题目
    • 992. K 个不同整数的子数组:给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定独立的子数组为好子数组。求 A 中好子数组的数目。可以使用两个滑动窗口分别统计不同整数个数小于等于 K 和小于等于 K - 1 的子数组数量,然后相减得到不同整数个数恰好为 K 的子数组数量。

4. 字符串匹配问题

  • 问题特征:在字符串匹配过程中,需要对连续的子字符串进行操作和判断。滑动窗口可以在字符串上滑动,检查每个窗口内的子字符串是否满足匹配条件。
  • 示例题目
    • 438. 找到字符串中所有字母异位词:给定两个字符串 sp,找到 s 中所有 p 的异位词的子串,返回这些子串的起始索引。使用滑动窗口在 s 上滑动,比较窗口内的字符频率和 p 的字符频率是否相同,从而找出所有的异位词子串。

判断是否使用滑动窗口的一般思路

  • 连续子结构:如果问题关注的是连续的子数组、子字符串等结构,那么可以考虑滑动窗口。
  • 动态调整:当需要根据当前窗口内的元素状态动态调整窗口的大小和位置时,滑动窗口通常是有效的方法。
  • 优化复杂度:如果使用暴力解法的时间复杂度较高(如 O ( n 2 ) O(n^2) O(n2) 或更高),而滑动窗口可以将时间复杂度优化到 O ( n ) O(n) O(n),那么滑动窗口是一个值得尝试的选择。
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int len=nums.length;
        int left=0,right=0;
        int sum=0;
        int res=Integer.MAX_VALUE;
        for(right=0;right<len;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;
    }
}

右边界必须遍历数组中的每个元素(不管当前 sum 是否满足条件),因为即使当前 sum < target,后续元素可能与前面的元素组成更短的子数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值