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

滑动窗口题目:长度最小的子数组

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
      • 进阶
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:长度最小的子数组

出处:209. 长度最小的子数组

难度

5 级

题目描述

要求

给定一个正整数数组 nums\texttt{nums}nums 和一个正整数 target\texttt{target}target,返回元素和大于等于 target\texttt{target}target连续子数组 [numsl,numsl+1,...,numsr-1,numsr]\texttt{[nums}_\texttt{l}\texttt{, nums}_\texttt{l + 1}\texttt{, ..., nums}_\texttt{r - 1}\texttt{, nums}_\texttt{r}\texttt{]}[numsl, numsl + 1, ..., numsr - 1, numsr] 的最小长度。如果不存在符合条件的子数组,返回 0\texttt{0}0

示例

示例 1:

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

示例 2:

输入:target=4,nums=[1,4,4]\texttt{target = 4, nums = [1,4,4]}target = 4, nums = [1,4,4]
输出:1\texttt{1}1

示例 3:

输入:target=11,nums=[1,1,1,1,1,1,1,1]\texttt{target = 11, nums = [1,1,1,1,1,1,1,1]}target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0\texttt{0}0

数据范围

  • 1≤target≤109\texttt{1} \le \texttt{target} \le \texttt{10}^\texttt{9}1target109
  • 1≤nums.length≤105\texttt{1} \le \texttt{nums.length} \le \texttt{10}^\texttt{5}1nums.length105
  • 1≤nums[i]≤105\texttt{1} \le \texttt{nums[i]} \le \texttt{10}^\texttt{5}1nums[i]105

进阶

如果你已经实现 O(n)\texttt{O(n)}O(n) 时间复杂度的解法, 请尝试实现 O(nlogn)\texttt{O(n log n)}O(n log n) 时间复杂度的解法。

解法一

思路和算法

由于数组 nums\textit{nums}nums 中的元素都是正整数,因此对于任意子数组,在子数组的任意一端添加元素(即增加子数组的长度)后子数组中的元素和一定增加,在子数组的任意一端删除元素(即减少子数组的长度)后子数组中的元素和一定减少。

考虑数组 nums\textit{nums}nums 的两个不同下标 end1\textit{end}_1end1end2\textit{end}_2end2,其中 end1<end2\textit{end}_1 < \textit{end}_2end1<end2,分别以这两个下标作为结束下标,寻找元素和大于等于 target\textit{target}target 的最短子数组,将这两个最短子数组的开始下标分别记为 start1\textit{start}_1start1start2\textit{start}_2start2,则必有 start1≤start2\textit{start}_1 \le \textit{start}_2start1start2(否则对于任意 start2<start3≤start1\textit{start}_2 < \textit{start}_3 \le \textit{start}_1start2<start3start1,下标范围 [start3,end2][\textit{start}_3, \textit{end}_2][start3,end2] 的子数组的元素和大于等于 target\textit{target}target,且长度小于下标范围 [start2,end2][\textit{start}_2, \textit{end}_2][start2,end2] 的子数组)。

因此,可以使用变长滑动窗口寻找数组 nums\textit{nums}nums 中的元素和大于等于 target\textit{target}target 的最短子数组。用 [start,end][\textit{start}, \textit{end}][start,end] 表示滑动窗口,初始时 start=end=0\textit{start} = \textit{end} = 0start=end=0。将滑动窗口的右端点 end\textit{end}end 向右移动,移动过程中维护滑动窗口的左端点 start\textit{start}start,对于每个 end\textit{end}end 寻找元素和大于等于 target\textit{target}target 的最小滑动窗口。

sum\textit{sum}sum 表示滑动窗口中的元素和。对于每个右端点 end\textit{end}end,执行如下操作。

  1. sum\textit{sum}sum 的值增加 nums[end]\textit{nums}[\textit{end}]nums[end]

  2. 如果 sum≥target\textit{sum} \ge \textit{target}sumtarget,则当前滑动窗口 [start,end][\textit{start}, \textit{end}][start,end] 中的子数组为元素和大于等于 target\textit{target}target 的子数组,其长度为 end−start+1\textit{end} - \textit{start} + 1endstart+1,使用当前子数组的长度更新子数组的最小长度,然后将 sum\textit{sum}sum 的值减少 nums[start]\textit{nums}[\textit{start}]nums[start],将 start\textit{start}start 向右移动一位,重复该操作直到 sum<target\textit{sum} < \textit{target}sum<target

遍历结束之后,可以得到数组 nums\textit{nums}nums 中的元素和大于等于 target\textit{target}target 的子数组的最小长度。

代码

class Solution {public int minSubArrayLen(int target, int[] nums) {int minLength = Integer.MAX_VALUE;int sum = 0;int start = 0, end = 0;int n = nums.length;while (end < n) {sum += nums[end];while (sum >= target) {minLength = Math.min(minLength, end - start + 1);sum -= nums[start];start++;}end++;}return minLength == Integer.MAX_VALUE ? 0 : minLength;}
}

复杂度分析

  • 时间复杂度:O(n)O(n)O(n),其中 nnn 是数组 nums\textit{nums}nums 的长度。滑动窗口的左右端点最多各遍历数组 nums\textit{nums}nums 一次。

  • 空间复杂度:O(1)O(1)O(1)

解法二

思路和算法

由于数组 nums\textit{nums}nums 中的元素都是正整数,因此子数组元素和的最大值为整个数组的元素和。如果整个数组的元素和小于 target\textit{target}target,则不存在元素和大于等于 target\textit{target}target 的子数组,返回 000。如果整个数组的元素和大于等于 target\textit{target}target,则一定存在元素和大于等于 target\textit{target}target 的子数组。

kkk 表示数组 nums\textit{nums}nums 的元素和大于等于 target\textit{target}target 的子数组的最小长度。由于数组 nums\textit{nums}nums 中的元素都是正整数,因此一定存在长度为 k+1k + 1k+1 的子数组的元素和大于等于 target\textit{target}target(当 kkk 等于数组 nums\textit{nums}nums 的长度时例外),且一定不存在长度小于 kkk 的子数组的元素和大于等于 target\textit{target}target。因此,这道题是二分查找判定问题,需要找到最小长度。

当子数组长度 xxx 固定时,可以使用长度为 xxx 的定长滑动窗口遍历数组 nums\textit{nums}nums,得到每个长度为 xxx 的子数组的元素和,并判断是否存在长度为 xxx 且元素和大于等于 target\textit{target}target 的子数组。具体做法如下。

  1. sum\textit{sum}sum 表示长度为 xxx 的子数组的元素和,初始时 sum\textit{sum}sum 等于最左侧的 xxx 个元素之和。

  2. 对于 x≤i<nx \le i < nxi<n,当子数组的下标范围从 [i−x,i−1][i - x, i - 1][ix,i1] 移动到 [i−x+1,i][i - x + 1, i][ix+1,i] 时,nums[i−x]\textit{nums}[i - x]nums[ix] 移出子数组,nums[i]\textit{nums}[i]nums[i] 移入子数组,因此 sum\textit{sum}sum 的变化是减少 nums[i−x]\textit{nums}[i - x]nums[ix] 并增加 nums[i]\textit{nums}[i]nums[i]

  3. 遍历所有的长度为 xxx 的子数组之后,即可得到每个长度为 xxx 的子数组的元素和,并判断是否存在长度为 xxx 且元素和大于等于 target\textit{target}target 的子数组。

low\textit{low}lowhigh\textit{high}high 分别表示二分查找的下界和上界。由于子数组至少有 111 个元素,因此 low\textit{low}low 的初始值等于 111;由于子数组的最大长度为整个数组的长度,因此 high\textit{high}high 的初始值等于数组 nums\textit{nums}nums 的长度。

每次查找时,取 mid\textit{mid}midlow\textit{low}lowhigh\textit{high}high 的平均数向下取整,判断是否存在长度为 mid\textit{mid}mid 且元素和大于等于 target\textit{target}target 的子数组,执行如下操作。

  • 如果存在长度为 mid\textit{mid}mid 且元素和大于等于 target\textit{target}target 的子数组,则最小长度 kkk 小于等于 mid\textit{mid}mid,因此在 [low,mid][\textit{low}, \textit{mid}][low,mid] 中继续查找。

  • 如果不存在长度为 mid\textit{mid}mid 且元素和大于等于 target\textit{target}target 的子数组,则最小长度 kkk 大于 mid\textit{mid}mid,因此在 [mid+1,high][\textit{mid} + 1, \textit{high}][mid+1,high] 中继续查找。

low=high\textit{low} = \textit{high}low=high 时,查找结束,此时 low\textit{low}low 即为最小长度 kkk

实现方面,由于只需要判断是否存在元素和大于等于 target\textit{target}target 的子数组,因此只要找到一个子数组的元素和大于等于 target\textit{target}target 即可提前返回。

代码

class Solution {public int minSubArrayLen(int target, int[] nums) {int total = Arrays.stream(nums).sum();if (total < target) {return 0;}int low = 1, high = nums.length;while (low < high) {int mid = low + (high - low) / 2;if (exists(target, nums, mid)) {high = mid;} else {low = mid + 1;}}return low;}public boolean exists(int target, int[] nums, int subarrayLen) {int sum = 0;int n = nums.length;for (int i = 0; i < subarrayLen; i++) {sum += nums[i];if (sum >= target) {return true;}}for (int i = subarrayLen; i < n; i++) {sum -= nums[i - subarrayLen];sum += nums[i];if (sum >= target) {return true;}}return false;}
}

复杂度分析

  • 时间复杂度:O(nlog⁡n)O(n \log n)O(nlogn),其中 nnn 是数组 nums\textit{nums}nums 的长度。当存在符合条件的子数组时,需要执行 O(log⁡n)O(\log n)O(logn) 次二分查找,每次二分查找需要 O(n)O(n)O(n) 的时间遍历数组 nums\textit{nums}nums,时间复杂度是 O(nlog⁡n)O(n \log n)O(nlogn)

  • 空间复杂度:O(1)O(1)O(1)


文章转载自:

http://0CPybNei.gLhtj.cn
http://BlVt8Kkd.gLhtj.cn
http://9Xaik4DU.gLhtj.cn
http://Gazed7Aq.gLhtj.cn
http://gMWQgiiG.gLhtj.cn
http://fJT02z1B.gLhtj.cn
http://9eVECY1h.gLhtj.cn
http://jlvhvaZq.gLhtj.cn
http://XWs3YHWG.gLhtj.cn
http://caPS9GXi.gLhtj.cn
http://fJEGkYTb.gLhtj.cn
http://vyTAf4wQ.gLhtj.cn
http://o1otUceD.gLhtj.cn
http://0w6qwGlk.gLhtj.cn
http://EEUjlDmT.gLhtj.cn
http://C93ms4Yi.gLhtj.cn
http://ubQvChOw.gLhtj.cn
http://XgYlpa2K.gLhtj.cn
http://wV7aLoif.gLhtj.cn
http://VbIyp13U.gLhtj.cn
http://oFt16Rtt.gLhtj.cn
http://b8LP6Kk5.gLhtj.cn
http://CWbbIdYD.gLhtj.cn
http://dSzOf0Id.gLhtj.cn
http://kvflVKp7.gLhtj.cn
http://QGmPcDiL.gLhtj.cn
http://OILPzuZS.gLhtj.cn
http://4SDTB5Oh.gLhtj.cn
http://ebSLmoRf.gLhtj.cn
http://yQYwAUDS.gLhtj.cn
http://www.dtcms.com/a/374150.html

相关文章:

  • 如何Maven 构建问题排查与依赖管理
  • 嵌入式学习日记(42)ARM
  • 盖奇的遭遇__[心理学和脑科学神经科学](1)
  • CSS-基础认知(基础篇)
  • 淘宝商品数据爬虫 API 实战开发指南:合规化采集与高效数据处理
  • BBEH:大模型高阶推理能力的“超难”试金石
  • 训诂学与现代人工智能的融合——学术价值、技术潜力与未来展望
  • 【面试题】Transformer创新应用
  • KGDB(Kernel GNU Debugger)工具使用方法详解
  • 架构思维升维:用三层模型穿透技术表象,驾驭复杂系统——淘宝亿级并发架构演进启示录
  • Java设计模式之结构型—装饰器模式
  • Python编程基础(八) | 类
  • Ubuntu1804安装SonarQube
  • commons-lang3
  • 分布式专题——4 大厂生产级Redis高并发分布式锁实战
  • Infortrend普安科技IEC私有云平台VM解决方案
  • 实战对比:百炼知识库与钉钉知识库的全方位对比
  • GitLab升级后仓库镜像信任证书导入问题
  • 2. 计算机系统基础知识
  • 软考中级习题与解答——第三章_操作系统(2)
  • 第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛--算法题科普
  • 【CentOS7】使用yum安装出错,报HTTPS Error 404 - Not Found
  • 今天继续学习shell脚本
  • 解决哈希冲突
  • C++算法专题学习:栈相关的算法
  • CentOS部署ELK Stack完整指南
  • 多模态大模型Keye-VL-1.5发布!视频理解能力更强!
  • JAK/STAT信号通路全解析:核心分子、激活与负调控
  • 人工智能知识图谱应用平台国家标准发布实施
  • Chiplet封装革命:路登多芯片同步固晶治具支持异构集成