长度最小的子数组

力扣题目链接(opens new window)

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

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

初见思路

题目给的输入有两个,一个是数组nums,另一个是目标和target。我们需要找到数组中的一个连续子数组,其相加和为target,且所需数组元素最少

两个问题:

1、寻找一个子数组,相加结果等于target

2、该子数组是所有可能数组中最小的

双指针好像不太行,用暴力破解试试

那就用两层for循环,第一层用于控制子数组的起始位置,第二层是子数组的结束位置【感觉本质上还是双指针。。。】

Java版(超时)

class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int subLeng = 0;//用于记录子串长度
int res = Integer.MAX_VALUE;//将res设置为int的最大值
for(int i = 0; i < nums.length; i++){
sum = 0;
for(int j = i; j < nums.length; j++){
sum += nums[j];
if(sum >= target){
subLeng = j - i + 1;
res = res < subLeng ? res : subLeng;//满足最小子串条件的才保留,显然如果出现subLeng一定会保存的因为不可能有比res大的值
break;
}
}
}
return res == Integer.MAX_VALUE ? 0 : res;//判定当前res是否还为初始值,是就输出0
}
}

不负众望的超时了,这也正常,毕竟两个for循环已经是O(n*n)的时间复杂度了

常规思路

这里就需要使用数组操作中的一个重要方法:滑动窗口

其本质上还是需要两个玩意去代表子数组的起始和结束位置

只不过使用滑动窗口方法我们可以在一个for循环中就实现上述功能,从而优化了时间复杂度

上面的描述更像双指针了,实际上滑动窗口确实就是双指针的一个变种,或者说只要你乐意,在一个数组上操控两个下标的方法都可以是双指针。

那么怎么做呢?

既然是双指针,那么肯定先确定两个指针各自需要干什么

设这里有两个指针left、right,分别表示窗口的左边界右边界

和之前的双指针用法类似,将某个指针放入for循环中作为遍历时的下标【那肯定是右边界比较合适】

当for循环不断移动右边界的位置时,我们同时计算两个边界内(即窗口内)的数的和

如果当前窗口中元素的和满足target,记录下其长度,与res比较【res的初始值设为整型下的最大值】

如果当前子串长度小于res,那么将更新res为当前子串的长度值【肯定更新啊,res都设成最大了,来什么值都会更新的】

然后移动左边界left,继续计算,不满足条件就移动右边界

总而言之,就是当条件不满足时,移动右边界去遍历整个数组,遇到条件满足的子数组,计算并更新res,然后移动左边界,重复上述过程。

以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程:

解题模板

滑动窗口的代码中的关键点如下:

  • 滑动窗口算法是基于双指针思想的一种算法
  • 用于保存记录窗口内数值和的变量res应该设置为整型的最大值
  • while缩小窗口大小

c++版

class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0;
int sum = 0;
int sumLen = 0;
int res = INT_MAX;
for(int right = 0; right < nums.size(); ++right){
sum += nums[right];//累加当前窗口内的值(因此right要从0开始)
while(sum >= target){//窗口内的和大于target,记录当前窗口大小
sumLen = right - left + 1;//要加1,因为right和left都是从0开始的
res = min(sumLen, res);//更新当前最小结果
//实现窗口"滑动"
// left++;//移动左指针,缩小窗口
sum -= nums[left];//sum -= nums[left++];
left++;
}
}
return res == INT_MAX? 0 : res;
}
};

二刷问题:

1、滑动窗口的原理遗忘

主要是怎么滑的给忘了,触发窗口滑动的情况应该是当前窗口内的值满足题目条件

2、滑动窗口的实现

本质上还是双指针,并且是一个指针在循环外的那种情况

左指针只有在窗口满足缩小条件时才会移动(要注意,在判断条件时必须使用while,因为窗口不可能只滑动一次,这个过程是连续的)

3、关于三目运算符

其本质上还是类似于if条件语句,因此需要使用"=="

例如

return res == INT_MAX? 0 : res;//判断res是否满足三目运算符中的条件
return res = INT_MAX? 0 : res;//错误用法

三刷问题:

1、窗口滑动时是连续的,因此要使用while而不是if

2、记录窗口长度的变量要和记录结果变量分开,不然有可能取到的不是最小值

int subLen = 0;
int res = INT_MAX;

Java版

ps:

  • 取最大值res使用Integer.MAX_VALUE
  • 使用Math.min比较并更新res(Java版)
  • Java下三目运算符:(关系表达式) ? 表达式1:表达式2;
先执行关系表达式,看其结果是true还是false
如果是true,则执行表达式1
如果是false,则执行表达式2
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int subLeng = 0;
int left = 0;
int res = Integer.MAX_VALUE;//将res设置为int的最大值
for(int right = 0; right < nums.length; right++){
sum += nums[right];//累加当前窗口内的数值
while(sum >= target){//当和大于等于target时,记录并更新res
subLeng = right - left + 1;
res = Math.min(res, subLeng);//更新res
sum -= nums[left++];//移动左边界缩小窗口,此处为算法核心
}
}
return res == Integer.MAX_VALUE ? 0 : res;//判定当前res是否还为初始值,是就输出0
}
}

Python版

ps:

  • Python中res需要取无限大的值,用float("inf")实现
  • range(len(nums))生成用于遍历的迭代体
  • 比较子串长度时使用min函数
  • 注意Python下三目运算符的写法:[statement_1] if [expression] else [statement_2]
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
sum = 0
left = 0 # 窗口左边界
res = float("inf") # 无限大的数,相当于java中的Integer.MAX_VALUE
for right in range(len(nums)):
sum += nums[right] # 累加窗口内的值
while sum >= target:
res = min(res, right - left + 1) # 比较当前子串和res的长度,取最小值
sum -= nums[left]
left += 1
return 0 if res == float("inf") else res # 判断res是否为初值

子数组最大平均数 I

代码

class Solution {
public:
double findMaxAverage(vector<int>& nums, int k) {
int sum = 0;
int maxSum = INT_MIN;
int left = 0; for(int right = 0; right < nums.size(); right++){
sum += nums[right];
if(right - left + 1 == k){//窗口大小到达k后,更新最大值
maxSum = max(maxSum, sum);
sum -= nums[left];
left++;
}
}
//最后计算平均值,分子分母均强转为double
return static_cast<double>(maxSum) / static_cast<double>(k);
}
};

【LeetCode数组#4滑动窗口】长度最小的子数组+子数组最大平均数I的更多相关文章

  1. 长度最小子数组-LeetCode209 滑动窗口

    力扣:https://leetcode.cn/problems/minimum-size-subarray-sum/ 题目 给定一个含有 n 个正整数的数组和一个正整数 target .找出该数组中满 ...

  2. 【LeetCode】480. 滑动窗口中位数 Sliding Window Median(C++)

    作者: 负雪明烛 id: fuxuemingzhu 公众号: 每日算法题 本文关键词:LeetCode,力扣,算法,算法题,滑动窗口,中位数,multiset,刷题群 目录 题目描述 题目大意 解题方 ...

  3. leetcode 209 3 滑动窗口

    class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { ,r=-; //由于数组是[]区间, ...

  4. 代码随想录训练营day 2 |977有序数组的平方 209.长度最小的子数组 (C++)

    977.有序数组的平方 题目链接:977.有序数组的平方 题目描述:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序. 例子如下: 输入 ...

  5. Leetcode 239题 滑动窗口最大值(Sliding Window Maximum) Java语言求解

    题目链接 https://leetcode-cn.com/problems/sliding-window-maximum/ 题目内容 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧 ...

  6. 【leetcode】239. 滑动窗口最大值

    目录 题目 题解 三种解法 "单调队列"解法 新增.获取最大值 删除 代码 题目 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以 ...

  7. LeetCode编程训练 - 滑动窗口(Sliding Window)

    滑动窗口基础 滑动窗口常用来解决求字符串子串问题,借助map和计数器,其能在O(n)时间复杂度求子串问题.滑动窗口和双指针(Two pointers)有些类似,可以理解为往同一个方向走的双指针.常用滑 ...

  8. 【Leetcode 二分】 滑动窗口中位数(480)

    题目 中位数是有序序列最中间的那个数.如果序列的大小是偶数,则没有最中间的数:此时中位数是最中间的两个数的平均数. 例如: [2,3,4],中位数是 3 [2,3],中位数是 (2 + 3) / 2 ...

  9. 滑动窗口解决最小子串问题 leetcode3. Longest Substring Without Repeating Characters

    问题描述: Given a string, find the length of the longest substring without repeating characters. Example ...

  10. 【LeetCode】209. 长度最小的子数组

    209. 长度最小的子数组 知识点:数组:前缀和:二分法:双指针:滑动窗口 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小 ...

随机推荐

  1. [转帖]crash工具分析Kdump下vmcore文件常用命令总结(三)(实例易懂)

    一.简介 本文主要介绍使用crash工具对kdump生成的vmcore文件进行分析,解析常见的crash命令,前面已讲述两章关于Kdump的内容,读者感兴趣可以点击下面的链接: 1.Kdump调试机理 ...

  2. [转帖]gdb 常用命令

    https://www.cnblogs.com/xvic/p/15997498.html 栈信息 不管是操作转储文件还是用GDB设置断点进行调试,都可以输入 (gdb)bt 打印栈内容进行查看.一般的 ...

  3. [转帖]SpecCPU2017 测试cpu性能

    https://www.bbsmax.com/A/GBJrxP1Ed0/ SpecCPU介绍见: https://blog.csdn.net/qq_36287943/article/details/1 ...

  4. PMC相关RAID卡信息查看方法

    PMC相关RAID卡信息查看方法 摘要 昨天简单整理了LSI相关设备的信息 今天计划学习下PMC相关的RAID卡信息. 也就是偶昨天storcli 查看 controller为0 的情况. 感觉部分服 ...

  5. Oracle 查看所有表大小的SQL

    Oracle 查看所有表大小的SQL 比较坑的是 lob 字段和 表的大小不在一个地方 为了出结果 我这边使用了 union all 慢的一逼... SELECT sum( tablesize ), ...

  6. JRC Flink流作业调优指南

    # 作者:京东物流 康琪 本文综合Apache Flink原理与京东实时计算平台(JRC)的背景,详细讲述了大规模Flink流作业的调优方法.通过阅读本文,读者可了解Flink流作业的通用调优措施,并 ...

  7. 从零开始配置 vim(3)—— 键盘映射进阶

    严格意义上来说,快捷键的绑定应该是键盘映射,将某些键映射为另一些键. 在上篇我们介绍了基本的键盘映射操作,知道了如何 :map.:imap.:vmap.:nmap这些命令来映射键盘快捷键.它们很方便, ...

  8. 复原docker中容器的启动命令

    复原 docker 容器的启动命令 前言 查看 docker 容器的启动命令 参考 复原 docker 容器的启动命令 前言 不规范的操作,在启动 docker 容器,没有留命令脚本,或者没有使用 d ...

  9. vue-cropper 移动端上传图片压缩裁剪

    头像裁剪压缩上传流程: 点击头像--判断是否为IOS端--若是--A,否则--BA:选择图片 --CB:弹框供用户选择从相册选择或者调用相机拍照--选择图片--CC:出现cropper裁剪框,裁剪框位 ...

  10. VB6的OfficeMenu控件 - 开源研究系列文章

    这次将原来VB6中喜欢和使用到的OfficeMenu的控件做一个使用介绍. 上次介绍了VB6中的控件引擎,但是那个只针对基本的控件,这个OfficeMenu控件在当时是收费的,笔者找度娘好不容易才下载 ...