LeetCode题练习与总结:长度最小的子数组--209

187 篇文章 0 订阅
119 篇文章 0 订阅

一、题目描述

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

二、解题思路

这是一个典型的滑动窗口问题。滑动窗口是一种常用的处理数组或链表问题的技术,它通过两个指针(通常称为快指针和慢指针)来维护一个窗口。在这个问题中,我们使用滑动窗口来找到长度最小的子数组,其元素之和大于等于目标值 target

步骤如下:

  1. 初始化两个指针 left 和 right,它们都指向数组的开始位置。
  2. 初始化一个变量 sum 用于记录当前窗口内的元素和。
  3. 初始化一个变量 minLength 用于记录满足条件的最小子数组长度,初始值可以设为 Integer.MAX_VALUE
  4. 使用 right 指针遍历数组,每次将 nums[right] 加到 sum 上。
  5. 当 sum 大于等于 target 时,更新 minLength 为当前窗口大小(即 right - left + 1),然后尝试通过将 left 指针向右移动来缩小窗口,同时更新 sum
  6. 当 right 指针遍历完数组后,如果 minLength 仍然是 Integer.MAX_VALUE,说明没有找到满足条件的子数组,返回 0;否则返回 minLength

三、具体代码

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int sum = 0;
        int minLength = Integer.MAX_VALUE;

        for (int right = 0; right < nums.length; right++) {
            sum += nums[right]; // 将当前元素加到sum上

            // 当sum大于等于target时,尝试缩小窗口
            while (sum >= target) {
                minLength = Math.min(minLength, right - left + 1); // 更新最小长度
                sum -= nums[left]; // 从sum中减去left指针指向的元素
                left++; // left指针右移
            }
        }

        // 如果minLength没有被更新,返回0;否则返回minLength
        return minLength == Integer.MAX_VALUE ? 0 : minLength;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • right 指针遍历数组一次,其操作是线性的,时间复杂度为 O(n),其中 n 是数组 nums 的长度。
  • 对于每个 right 指针的位置,left 指针最多只会从数组的起始位置移动到 right 指针的位置,因此对于每个 right 指针的位置,left 指针的操作也是线性的。
  • 由于 left 指针在遍历过程中不会超过 right 指针,因此 left 指针的总移动次数不会超过 n,即 left 指针的总操作次数是 O(n)。
  • 综合以上两点,总的时间复杂度是 O(n) + O(n) = O(n)。
2. 空间复杂度
  • leftrightsum 和 minLength 都是固定数量的整型变量,它们占用常数空间,空间复杂度为 O(1)。
  • 该算法没有使用任何与输入数组大小相关的数据结构,如额外的数组或集合。
  • 因此,总的空间复杂度是 O(1)。

五、总结知识点

  • 数组遍历

    • 使用 for 循环来遍历数组 nums 的所有元素。
  • 指针操作

    • 使用两个指针 left 和 right 来表示滑动窗口的左右边界。
    • right 指针用于扩展窗口,left 指针用于收缩窗口。
  • 累加和

    • 使用变量 sum 来存储当前窗口内所有元素的和。
  • 最小值更新

    • 使用 Math.min() 方法来更新 minLength,以找到满足条件的最小子数组长度。
  • 条件判断

    • 使用 while 循环来判断当前窗口的元素和是否大于等于 target,并在满足条件时收缩窗口。
  • 整数比较

    • 使用 Integer.MAX_VALUE 来初始化 minLength,这是一个常用的技巧,用于在没有找到满足条件的子数组时返回 0。
  • 逻辑运算

    • 使用三元运算符 ?: 来决定返回值,如果 minLength 没有被更新(仍然是 Integer.MAX_VALUE),则返回 0;否则返回 minLength

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

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

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

打赏作者

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

抵扣说明:

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

余额充值