209. 长度最小的子数组

209. 长度最小的子数组

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
    // sort(nums.begin(),nums.end())    不能先排序再进行操作,题目要求的是连续子数组
    //使用快慢指针
    int left =0;
    int n = nums.size();
    int sum =0;
    int len =INT32_MAX;//初始化长度为int类型的最大整数
    for(int right = 0;right<n;right++){
        sum +=nums[right];
        while(sum>=target){
            sum-=nums[left];
            len = min(len,right-left+1);
            left++;
        }
    }
    return len == INT32_MAX?0:len;
    }
};

是的,除了暴力法(O(n^2))外,还有一种 更高效的方法 ,即使用 滑动窗口(双指针法) ,时间复杂度可以优化到 O(n)。

滑动窗口法(双指针法):

滑动窗口法的核心思想是维护一个动态窗口,窗口内的元素的和不断扩展和缩小,直到找到满足条件的子数组。具体来说,我们使用两个指针,分别表示窗口的左右边界,通过扩展右边界来增加窗口的元素,并根据当前窗口和的大小决定是否需要收缩左边界。

具体步骤:
  1. 使用两个指针 left 和 right 表示窗口的左右边界。初始时,left = 0,right = 0。
  2. 不断增加右指针,将 nums[right] 加到当前窗口的和中。
  3. 每当当前窗口的和大于或等于 s 时,尝试缩小窗口(通过移动左指针),并更新最短子数组长度。
  4. 继续扩展右指针,直到遍历完整个数组。
优点:
  • 时间复杂度:O(n) :每个元素最多被左右指针访问一次,因此总时间复杂度为 O(n)。
  • 空间复杂度:O(1):只用了常数级别的额外空间。
代码实现:
复制代码
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size();
        int result = INT32_MAX; // 最小子数组长度
        int sum = 0;            // 当前窗口的和
        int left = 0;           // 左指针

        for (int right = 0; right < n; ++right) {
            sum += nums[right];  // 增加右指针的元素到窗口和中

            // 当窗口和 >= s 时,尝试收缩窗口,更新最小长度
            while (sum >= s) {
                result = min(result, right - left + 1);  // 更新最小子数组长度
                sum -= nums[left];  // 缩小窗口,减少左边的元素
                left++;  // 左指针右移
            }
        }

        // 如果 result 没有更新,说明没有找到符合条件的子数组,返回 0
        return result == INT32_MAX ? 0 : result;
    }
};

代码解析:

  1. 初始化:

    • result 用来存储满足条件的最短子数组长度,初始为 INT32_MAX。
    • sum 用来存储当前滑动窗口的和,初始为 0。
    • left 是左指针,表示窗口的左边界,初始为 0。
  2. 右指针遍历数组:

    • 外层循环的 right 指针遍历数组的每个元素,通过 sum += nums[right] 扩展当前窗口的和。
  3. 判断和是否满足条件:

    • 每当 sum >= s 时,说明当前窗口的和已经满足题目的要求,可以尝试收缩窗口,更新最短子数组长度 result。
    • 在 while (sum >= s) 循环中,左指针 left 右移,减去 nums[left],即收缩窗口,直到 sum 小于 s 为止。每次都更新 result 为当前窗口的长度 right - left + 1 和之前的最小值。
  4. 返回结果:

    • 如果 result 仍然是初始的 INT32_MAX,说明没有找到符合条件的子数组,返回 0。
    • 否则,返回最短的符合条件的子数组的长度。

示例:

假设 nums = [2, 3, 1, 2, 4, 3] 和 s = 7,下面是滑动窗口的执行过程:

  • 初始化:

    • left = 0, sum = 0, result = INT32_MAX
  • 右指针遍历:

    • right = 0:sum += 2,sum = 2(不满足条件)
    • right = 1:sum += 3,sum = 5(不满足条件)
    • right = 2:sum += 1,sum = 6(不满足条件)
    • right = 3:sum += 2,sum = 8(满足条件)
      • 进入 while (sum >= 7):
        • result = min(INT32_MAX, 3 - 0 + 1) = 4
        • sum -= 2,left++,sum = 6(不满足条件,退出 while)
    • right = 4:sum += 4,sum = 10(满足条件)
      • 进入 while (sum >= 7):
        • result = min(4, 4 - 1 + 1) = 3
        • sum -= 3,left++,sum = 7(满足条件)
        • result = min(3, 5 - 2 + 1) = 2
        • sum -= 1,left++,sum = 6(不满足条件,退出 while)
    • right = 5:sum += 3,sum = 9(满足条件)
      • 进入 while (sum >= 7):
        • result = min(2, 5 - 3 + 1) = 2
        • sum -= 2,left++,sum = 7(满足条件)
        • result = min(2, 6 - 4 + 1) = 2
        • sum -= 4,left++,sum = 3(不满足条件,退出 while)
  • 返回结果 :result = 2,返回 2。

时间复杂度:

  • 时间复杂度:O(n) :每个元素最多被左右指针访问一次,因此总时间复杂度为 O(n),其中 n 是数组的长度。

空间复杂度:

  • 空间复杂度:O(1):只使用了常数级别的额外空间。

总结:

总结:

  • 滑动窗口法(双指针法)比暴力法更高效,时间复杂度由 O(n^2) 降低到 O(n),适用于此类连续子数组和问题,特别是在处理较大数组时能够显著提高性能。

  • 这行代码的作用是判断是否找到了符合条件的子数组,如果没有找到符合条件的子数组,就返回 0。具体来说:

    复制代码
    return result == INT32_MAX ? 0 : result;

    解释:

  • result == INT32_MAX :

    这里的 result 最开始被初始化为 INT32_MAX,即 int 类型的最大值(通常为 2147483647)。INT32_MAX 是一个非常大的值,通常用作一个"哨兵值"来标记某个变量是否已经被更新过。在整个过程中,result 会被更新为最小符合条件的子数组长度。如果没有找到符合条件的子数组,result 仍然保持为这个初始值。

  • ? 0 : result:

    • 如果 result 没有被更新过,还是等于 INT32_MAX,说明没有找到符合条件的子数组,这时就返回 0。
    • 如果 result 已经被更新过,说明找到了一个符合条件的子数组,那么就返回 result,即最短符合条件的子数组长度。
  • 这行代码的目的是在没有找到符合条件的子数组时返回 0,否则返回最短的符合条件的子数组的长度。

相关推荐
古法老登瞎折腾2 小时前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
飞Link2 小时前
什么是 AirSim?一文读懂无人机仿真平台
python·算法·无人机
智能运维指南3 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks3 小时前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵4 小时前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设4 小时前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都4 小时前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
鱼宵4 小时前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作
一去不复返的通信er4 小时前
贪心算法-合并区间(LeetCode 56)
算法·leetcode·贪心算法
白山编程大哥4 小时前
Java 后端如何优雅地把 List 集合返回给前端
java·前端·list