当前位置: 首页 > news >正文

滑动窗口法的优化与实战——力扣209.长度最小的子数组


力扣209.长度最小的子数组在这里插入图片描述

题目解析

给定一个正整数数组 nums 和一个目标值 target,找出满足其总和大于等于 target最短连续子数组的长度。如果不存在符合条件的子数组,返回 0


我的初始代码(滑动窗口法)

初步思路

我一开始尝试用双指针 leftright 维护一个滑动窗口。初始化时,numbers = nums[left] 表示当前窗口的总和。当总和小于 target 时,右移 right 并累加;当总和大于等于 target 时,记录当前窗口长度,并左移 left 收缩窗口。

初始代码
class Solution {public int minSubArrayLen(int target, int[] nums) {int left = 0, right = 0;int minCount = nums.length + 1;int numbers = nums[left];if (numbers >= target) {return 1;}while (left < nums.length) {if (right < nums.length && numbers < target) {if (++right < nums.length) {numbers += nums[right];} else {break;}continue;}if (right < nums.length && numbers >= target) {minCount = minCount < right - left + 1 ? minCount : right - left + 1;numbers -= nums[left++];}if (minCount == 1) {return 1;}}if (minCount > nums.length) {return 0;}return minCount;}
}

在这里插入图片描述

但这里有个问题:每次只收缩一次窗口,可能遗漏更短的子数组。


优化后的滑动窗口法

思路改进

意识到问题后,我决定调整窗口收缩逻辑:只要总和仍大于等于 target,就持续左移 left,直到总和不再满足条件。这样可以确保每次找到最小的窗口长度。

优化后的代码
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]; // 扩展窗口// 持续收缩窗口while (sum >= target) {int windowLength = right - left + 1;minLength = Math.min(minLength, windowLength);sum -= nums[left];left++;}}return minLength == Integer.MAX_VALUE ? 0 : minLength;}
}

在这里插入图片描述

改进点
  1. 持续收缩窗口:通过 while 循环不断左移 left,直到总和小于 target,确保所有可能的最短窗口都被覆盖。
  2. 逻辑简化:去除了复杂的 if-else 分支,代码更易读。
  3. 边界处理:使用 Integer.MAX_VALUE 初始化 minLength,避免额外判断。

其他可行解法

前缀和 + 二分查找
  • 思路:构建前缀和数组,对每个右端点,用二分查找寻找最小的左端点。
  • 适用场景:正整数数组,需 O(n log n) 解法。
  • 代码
java
class Solution {public int minSubArrayLen(int target, int[] nums) {int n = nums.length;int[] prefixSum = new int[n + 1];// 构建前缀和数组for (int i = 1; i <= n; i++) {prefixSum[i] = prefixSum[i - 1] + nums[i - 1];}int minLen = Integer.MAX_VALUE;for (int right = 1; right <= n; right++) {int s = prefixSum[right] - target; int leftIndex = binarySearch(prefixSum, s, 0, right); if (leftIndex != -1) {minLen = Math.min(minLen, right - leftIndex);}}return minLen == Integer.MAX_VALUE ? 0 : minLen;}// 二分查找:找最大的 left 使得 prefixSum[left] <= sprivate int binarySearch(int[] prefixSum, int s, int left, int right) {int res = -1;while (left <= right) {int mid = left + (right - left) / 2;if (prefixSum[mid] <= s) {res = mid; // 记录满足条件的索引left = mid + 1; // 继续向右找更大的 left} else {right = mid - 1;}}return res;}
}

在这里插入图片描述
在这里插入图片描述

暴力解法(不推荐)
  • 思路:遍历所有子数组,计算其和。
  • 缺点:时间复杂度 O(n²),仅适用于小规模数据。
  • 代码
class Solution {public int minSubArrayLen(int target, int[] nums) {int n = nums.length;int minLen = Integer.MAX_VALUE;for (int i = 0; i < n; i++) {int sum = 0;for (int j = i; j < n; j++) {sum += nums[j];if (sum >= target) {minLen = Math.min(minLen, j - i + 1);break;}}}return minLen == Integer.MAX_VALUE ? 0 : minLen;}
}

在这里插入图片描述


总结与对比

方法时间复杂度空间复杂度是否推荐适用场景
初始代码(滑动窗口)O(n)O(1)⚠️单次窗口收缩,逻辑较复杂
优化后滑动窗口法O(n)O(1)最优解,所有正整数数组通用
前缀和 + 二分查找O(n log n)O(n)⚠️正整数数组,需 O(n log n) 解法
暴力解法O(n²)O(1)小规模数据(n ≤ 10³)

最终建议

滑动窗口法 是本题的首选解法。通过持续收缩窗口,可以高效地找到最短子数组,且时间复杂度为 O(n),空间复杂度为 O(1)。对于其他场景(如包含负数或需要 O(n log n) 解法),可考虑前缀和 + 二分查找。

http://www.dtcms.com/a/388825.html

相关文章:

  • 【Spring Boot 报错已解决】org.yaml.snakeyaml.scanner.ScannerException 报错原因与解决方案
  • 国家统计局数据读取——数据读取——清洗数据06
  • 基于 scratch 构建简单镜像
  • Web安全的暗角:10大易忽略逻辑漏洞解析!
  • 矩阵奇异值分解算法(SVD)详解
  • 【FreeRTOS】 二值信号量与互斥量(CMSIS-RTOS v2 版本)
  • Qt C++ :Qt全局定义<QtGlobal>
  • 【STL源码剖析】从源码看 list:从迭代器到算法
  • MySQL 专题(三):事务与锁机制深度解析
  • 使用BLIP训练自己的数据集(图文描述)
  • Geoserver修行记--在geoserver中如何复制某个图层组内容
  • DBG数据库透明加密网关:SQLServer应用免改造的安全防护方案,不限制开发语言的加密网关
  • 不同上位开发语言、PLC下位平台、工业协议与操作系统平台下的数据类型通用性与差异性详解
  • 【入门篇|第二篇】从零实现选择、冒泡、插入排序(含对数器)
  • javaweb Servlet基本介绍及开发流程
  • MySQL MHA高可用
  • 整体设计 逻辑拆解之2 实现骨架:一元谓词+ CNN的谓词系统
  • SpEL(Spring Expression Language)学习笔记
  • Java 字节码进阶3:面向对象多态在字节码层面的原理?
  • Tensor :核心概念、常用函数与避坑指南
  • 机器学习实战·第四章 训练模型(1)
  • 一次因表单默认提交导致的白屏排查记录
  • Linux:io_uring
  • 《第九课——C语言判断:从Java的“文明裁决“到C的“原始决斗“——if/else的生死擂台与switch的轮盘赌局》
  • 学习日报|Spring 全局异常与自定义异常拦截器执行顺序问题及解决
  • Spring Boot 参数处理
  • Debian系统基本介绍:新手入门指南
  • Spring Security 框架
  • Qt QPercentBarSeries详解
  • RTT操作系统(3)