leetcode 862. 和至少为 K 的最短子数组

news2025/5/25 18:14:01

这段代码使用了前缀和+单调队列的组合策略来高效解决"和至少为K的最短子数组"问题。我将从问题定义、核心思路到代码实现逐步拆解:

问题定义

给定数组 nums 和整数 k,找到和 ≥k最短非空子数组,返回其长度。
示例nums = [2,-1,2], k = 3 → 子数组 [2,-1,2] 和为3,长度3,返回3。

核心思路

1. 前缀和数组

前缀和数组 prefix[i] 表示 numsi 个元素的和。

  • 作用:快速计算子数组和。子数组 nums[i..j] 的和 = prefix[j+1] - prefix[i]
  • 示例nums = [2,-1,2]prefix = [0, 2, 1, 3]
    子数组 [2,-1] 的和 = prefix[2] - prefix[0] = 1 - 0 = 1
2. 单调队列的作用

单调队列 q 存储前缀和数组的下标,确保队列中的下标对应的前缀和严格递增

  • 目标:对于每个右边界 j,快速找到满足 prefix[j] - prefix[i] ≥k最大左边界 i(使子数组长度 j-i 最小)。
  • 优化逻辑
    1. 淘汰不可能的左边界:若存在 i1 < i2prefix[i1] ≥ prefix[i2],则 i1 永远不可能是最优解(因为 i2 更靠右且前缀和更小,使差值更大)。
    2. 单调性加速查询:队列中前缀和递增,若队首 i 不满足条件,则后续元素更不可能满足,直接停止检查。

代码实现解析

int shortestSubarray(vector<int>& nums, int k) {
    int n = nums.size();
    // 计算前缀和数组
    vector<long long> prefix(n + 1, 0);
    for (int i = 0; i < n; ++i) {
        prefix[i + 1] = prefix[i] + nums[i];
    }
    
    deque<int> q;  // 存储前缀和数组的下标,按prefix值单调递增
    int ans = INT_MAX;
    
    for (int j = 0; j <= n; ++j) {
        // 移除队尾较大的元素,保持队列单调性
        while (!q.empty() && prefix[j] <= prefix[q.back()]) {
            q.pop_back();
        }
        
        // 检查队首是否满足条件,更新最短长度
        while (!q.empty() && prefix[j] - prefix[q.front()] >= k) {
            ans = min(ans, j - q.front());
            q.pop_front();  // 队首已经找到最优解,后续无需再考虑
        }
        
        q.push_back(j);  // 将当前下标加入队列
    }
    
    return ans == INT_MAX ? -1 : ans;
}
关键步骤详解
  1. 前缀和计算
    prefix[i+1] = prefix[i] + nums[i],确保 prefix[j+1] - prefix[i] 表示子数组 nums[i..j] 的和。

  2. 维护单调队列

    • 移除队尾较大元素:若 prefix[j] ≤ prefix[q.back()],则弹出队尾。
      目的:保持队列单调性,确保后续查询时队首是最小前缀和。
    • 检查队首条件:若 prefix[j] - prefix[q.front()] ≥k,则更新最短长度并弹出队首。
      原理:队首是当前最小前缀和,若其不满足条件,则后续元素更不可能满足;若满足,则队首是当前最优左边界(对应最短长度),弹出后不再考虑。
  3. 添加当前下标
    j 加入队列尾部,确保队列中的下标按前缀和递增。

示例演示

输入nums = [2,-1,2], k = 3
前缀和prefix = [0, 2, 1, 3]

jprefix[j]队列 q操作最短长度
00[0]初始化队列
12[0, 1]2-0=2<3,加入1
21[0, 2]弹出1(1≥2),加入2
33[2, 3]3-0=3≥3 → 长度3-0=33

复杂度分析

  • 时间复杂度:O(n)。每个元素最多入队和出队一次。
  • 空间复杂度:O(n)。队列最坏情况下存储所有下标。

关键点总结

  1. 前缀和:将子数组和转化为前缀和的差值,O(1)时间计算。
  2. 单调队列
    • 单调性:确保队列中的前缀和递增,队首是最小前缀和。
    • 淘汰机制:移除不可能的左边界,加速查询。
  3. 队首弹出逻辑:一旦队首满足条件,其对应的是当前最短长度,后续无需再考虑,直接弹出。

这种方法高效解决了子数组和的优化问题,是处理类似问题的经典策略。

在这段代码中,使用 while 循环而非 if 是由单调队列的性质问题的最优解特性共同决定的。以下是详细分析:

一、为什么必须用 while 循环?

场景假设

假设队列 q 中存储的前缀和下标为 [i1, i2, i3],对应的前缀和满足 prefix[i1] < prefix[i2] < prefix[i3](队列递增)。
当遍历到 j 时,prefix[j] - prefix[i1] ≥k,说明:

  • i1 是可行的左边界,对应子数组长度为 j - i1
  • 由于 prefix[i2] > prefix[i1],则 prefix[j] - prefix[i2] < prefix[j] - prefix[i1],但可能仍 ≥k
    例如:prefix[j]=10, prefix[i1]=2, prefix[i2]=5, k=310-2=8≥3, 10-5=5≥3

结论:队首 i1 满足条件时,后续的 i2i3 可能也满足条件,且对应的子数组长度更短(因为 i2 > i1j-i2 < j-i1)。
因此需要持续检查队首之后的元素,直到找到不满足条件的队首,才能保证不会遗漏更优解。

二、while 循环的核心作用

1. 找到所有可行的左边界

队列中的前缀和递增,因此当 prefix[j] - prefix[q.front()] ≥k 时:

  • 队首是当前最小的前缀和,对应最大的可行左边界 q.front()(子数组长度最短)。
  • 但后续元素的前缀和更大,可能仍满足条件,且对应更短的子数组。

示例
prefix = [0, 1, 3, 5], k=2, j=3prefix[j]=5)。

  • 队首 i=05-0=5≥2 → 长度3-0=3。
  • 弹出队首后,新队首 i=15-1=4≥2 → 长度3-1=2(更优)。
  • 弹出队首后,新队首 i=25-3=2≥2 → 长度3-2=1(最优)。
  • 最终队列为 [3],循环停止。

若用 if 仅检查一次队首,会漏掉后续更优的解(如长度2和1)。

2. 维护队列的单调性和有效性

每次弹出队首后,新的队首可能仍满足条件,需要继续检查:

  • 队首一旦不满足条件,后续元素的前缀和更大,差值更小,必然不满足条件,循环可以终止。
  • 队首满足条件时,弹出队首是安全的,因为:
    • 该队首对应的子数组长度是当前可行解中最短的(因为队首是最大的左边界)。
    • 后续的左边界 i 更大(i > q.front()),对应的子数组长度更小,可能更优。

三、若用 if 会发生什么?

错误示例
// 错误:用if替代while
if (!q.empty() && prefix[j] - prefix[q.front()] >= k) {
    ans = min(ans, j - q.front());
    q.pop_front();
}

场景
prefix = [0, 2, 3], k=2, j=2prefix[j]=3)。

  • 队首 i=03-0=3≥2 → 记录长度2-0=2,弹出队首。
  • 此时队列变为 [1]prefix[1]=23-2=1<2,不满足条件。
  • 正确解:子数组 [2](下标1-1),和为2,长度1。
  • 错误原因:用 if 仅检查初始队首,未发现后续队首 i=1 可能满足条件(虽然本例中不满足,但存在其他情况)。

结论if 只能处理队首的单次检查,无法处理队列中多个连续满足条件的元素,导致遗漏更优解。

四、代码中的逻辑正确性

while (!q.empty() && prefix[j] - prefix[q.front()] >= k) {
    ans = min(ans, j - q.front()); // 记录当前最优解(可能不是全局最优)
    q.pop_front(); // 弹出队首,检查下一个元素
}
  • 循环条件:只要队首满足条件,就继续检查。
  • 操作顺序:先记录解,再弹出队首。
    • 因为队首是当前最大的左边界,对应的长度最短,弹出后新队首可能更优(长度更短)。
    • 例如:队首 i1 对应长度 L1,下一个队首 i2 > i1 对应长度 L2 < L1,必须记录 L2

五、总结:while 的必要性

  1. 处理多个连续可行解:队列中可能存在多个满足条件的左边界,while 确保遍历所有可能。
  2. 利用单调性剪枝:一旦队首不满足条件,后续元素必然不满足,直接终止循环,不会增加额外开销。
  3. 确保最优解:通过持续弹出队首,每次记录当前最短长度,最终得到全局最优解。

因此,while 循环是该算法正确性的关键,不能用 if 替代。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385512.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CodeBuddy 实现图片转素描手绘工具

本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前言 最近在社交媒体上&#xff0c;各种素描风格的图片火得一塌糊涂&#xff0c;身边不少朋友都在分享自己的 “素描照”&#xff0c;看着那些黑白线条勾勒出的独特韵味&a…

3.8.2 利用RDD计算总分与平均分

在本次实战中&#xff0c;我们利用Spark的RDD完成了成绩文件的总分与平均分计算任务。首先&#xff0c;准备了包含学生成绩的文件并上传至HDFS。接着&#xff0c;通过交互式方式逐步实现了成绩的读取、解析、总分计算与平均分计算&#xff0c;并最终输出结果。此外&#xff0c;…

29-FreeRTOS事件标志组

一、概述 事件是一种实现任务间通信的机制&#xff0c;主要用于实现多任务间的同步&#xff0c;但事件通信只能是事件类型的通信&#xff0c;无数据传输。与信号量不同的是&#xff0c;它可以实现一对多&#xff0c;多对多的同步。 即一个任务可以等待多个事件的发生&#xff1…

「EMD/EEMD/VMD 信号分解方法 ——ECG信号处理-第十四课」2025年5月23日

一、引言 上一节&#xff0c;我们介绍了希尔伯特黄变换&#xff08;HHT&#xff09;及其经验模态分解&#xff08;EMD&#xff09;的相关内容&#xff0c;这一节&#xff0c;我们继续拓展EMD分解技术&#xff0c;补充介绍集合经验模态分解&#xff08;Ensemble Empirical Mode …

二叉树层序遍历6

INT_MIN的用法&#xff1a; INT_MIN是C/C 中的一个宏常量 &#xff0c;在 <limits.h> &#xff08;C 中也可使用 <climits> &#xff09;头文件中定义&#xff0c;代表 int 类型能表示的最小整数值 。其用法主要体现在以下方面&#xff1a; 1.初始化变量 …

【论文精读】2023 AAAI--FastRealVSR现实世界视频超分辨率(RealWorld VSR)

文章目录 一、摘要二、Method2.1 现象&#xff08;问题&#xff09;--对应文中隐状态的分析&#xff08;Analysis of Hidden State&#xff09;2.2 怎么解决 --对应文中Framework2.2.1 整体流程&#xff1a;2.2.2 HSA模块怎么工作&#xff1f;2.2.2.1 隐藏状态池2.2.2.2 选择性…

IPython 常用魔法命令

文章目录 IPython 魔法命令&#xff08;Magic Commands&#xff09;一、系统与文件操作1. %ls2. %cd​​和%pwd3. %%writefile​​4. %run 二、性能分析与计时1. %timeit2. %prun​​3. ​​%%timeit 三、代码处理与交互1. %load2. ​​%edit3. ​​%store 四、调试与诊断2. ​…

Java虚拟机 - 程序计数器和虚拟机栈

运行时数据结构 Java运行时数据区程序计数器为什么需要程序计数器执行流程虚拟机栈虚拟机栈作用虚拟机栈核心结构运行机制 Java运行时数据区 首先介绍Java运行时数据之前&#xff0c;我们要了解&#xff0c;对于计算机来说&#xff0c;内存是非常重要的资源&#xff0c;因为内…

新能源汽车产业链图谱分析

1. 产业定义 新能源汽车是指采用非常规的车用燃料作为动力来源&#xff0c;综合车辆的动力控制和驱动方面的先进技术&#xff0c;形成的具有新技术、新结构、技术原理先进的汽车。 新能源车包括四大类型&#xff1a;混合动力电动汽车&#xff08;HEV&#xff09;、纯电动汽车…

如何在PyCharm2025中设置conda的多个Python版本

前言 体验的最新版本的PyCharm(Community)2025.1.1&#xff0c;发现和以前的版本有所不同。特别是使用Anaconda中的多个版本的Python的时候。 关于基于Anaconda中多个Python版本的使用&#xff0c;以及对应的Pycharm&#xff08;2023版&#xff09;的使用&#xff0c;可以参考…

maven快速上手

之前我们项目如果要用到其他额外的jar包&#xff0c;需要自己去官网下载并且导入。但是有maven后&#xff0c;直接在maven的pom.xml文件里用代码配置即可&#xff0c;配置好后maven会自动帮我们联网下载并且会自动导入该jar包 在右边的maven中&#xff0c;我们可以看到下载安装…

cplex12.9 安装教程以及下载

cplex 感觉不是很好找&#xff0c;尤其是教育版&#xff0c;我这里提供一个版本&#xff0c;在下面的图可以看到&#xff0c;不仅可以配置matlab&#xff0c;也可以配置vs,现在拿vs2017来测试一下&#xff0c;具体文件的文件有需要的可以复制下面的链接获取 我用网盘分享了「c…

甘特图实例 dhtmlxGantt.js

本文介绍了如何使用dhtmlxGantt库创建一个基础的甘特图示例&#xff0c;并对其进行汉化和自定义配置。首先&#xff0c;通过引入dhtmlxgantt.css和dhtmlxgantt.js文件初始化甘特图。接着&#xff0c;通过设置gantt.i18n.setLocale("cn")实现核心文本的汉化&#xff0…

视频剪辑 VEGAS - 配置视频片段保持原长宽比

VEGAS 配置视频片段保持原长宽比 右击视频片段 -> 选择【开关】 -> 勾选【保持长宽比】 右击视频片段 -> 点击【属性】 -> 弹出【属性】窗口 点击【媒体】 -> 选择【像素宽高比】为【1,0000&#xff08;方形&#xff09;】

力扣 54 .螺旋矩阵

文章目录 题目介绍题解 题目介绍 题解 代码如下&#xff1a; class Solution {public List<Integer> spiralOrder(int[][] matrix) {List<Integer> res new ArrayList<>();if (matrix.length 0){return res;}int l 0, r matrix[0].length - 1, t 0, b…

四、【API 开发篇 (上)】:使用 Django REST Framework 构建项目与模块 CRUD API

【API 开发篇 】&#xff1a;使用 Django REST Framework 构建项目与模块 CRUD API 前言为什么选择 Django REST Framework (DRF)&#xff1f;第一步&#xff1a;创建 Serializers (序列化器)第二步&#xff1a;创建 ViewSets (视图集)第三步&#xff1a;配置 URLs (路由)第四步…

ARM笔记-ARM伪指令及编程基础

第四章 ARM伪指令及编程基础 4.1 伪指令概述 4.1.1 伪指令定义 人们设计了一些专门用于指导汇编器进行汇编工作的指令&#xff0c;由于这些指令不形成机器码指令&#xff0c;它们只是在汇编器进行汇编工作的过程中起作用&#xff0c;所以被叫做伪指令。 4.1.2 伪指令特征 …

Python入门手册:Python基础语法

Python是一种简洁、易读且功能强大的编程语言&#xff0c;非常适合初学者入门。无论你是编程新手&#xff0c;还是有一定编程基础但想学习Python的开发者&#xff0c;掌握Python的基础语法都是迈向高效编程的第一步。本文将详细介绍Python的基本语法&#xff0c;包括变量和数据…

CAD如何导出PDF?PDF如何转CAD?详细教程来了

浩辰CAD看图王是一款功能强大的CAD图纸查看与编辑工具&#xff0c;其核心功能之一便是支持CAD与PDF格式的互转。下面是CAD看图王输出PDF和PDF转CAD功能的详细介绍及操作步骤&#xff1a; 一、输出PDF功能 看图王可以将CAD图纸转换为PDF格式&#xff0c;是文件在不同的设备上显…

python-数据可视化(大数据、数据分析、可视化图像、HTML页面)

通过 Python 读取 XLS 、CSV文件中的数据&#xff0c;对数据进行处理&#xff0c;然后生成包含柱状图、扇形图和折线图的 HTML 报告。这个方案使用了 pandas 处理数据&#xff0c;matplotlib 生成图表&#xff0c;并将图表嵌入到 HTML 页面中。 1.XSL文件生成可视化图像、生成h…