长度最小的子数组

力扣题目链接(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. [转帖]linux下 进程io队列,IO队列和IO调度

    IO体系概览 先看看本文主题IO调度和IO队列处于整个IO体系的哪个位置,这个IO体系是非常重要的,了解IO体系我们可以对整个IO过程有个全面的认识.虽然一下两下并不清楚IO体系各个部分的细节,但是我 ...

  2. [转帖]kubelet 原理解析六: 垃圾回收

    https://segmentfault.com/a/1190000022163856 概述 在k8s中节点会通过docker pull机制获取外部的镜像,那么什么时候清除镜像呢?k8s运行的容器又是 ...

  3. 我在京东做研发 | 京东云算法科学家解析爆火的ChatGPT

    令人惊艳的ChatGPT横空出世 背后有怎样的前沿技术支撑 走向大规模产品应用又有何局限 深耕对话式AI技术十余年 京东云算法科学家将带您一同走进技术世界 解析ChatGPT的技术亮点与局限 分享下一 ...

  4. rel分支合并进入dev分支有冲突怎么处理?

    rel分支合并进入dev分支有冲突怎么处理? 切换到本地rel 拉取远端rel 切换本地dev 拉去远端dev git merge rel 会出现冲突 解决后 推送到远端就可以

  5. es7如何使用await发送请求

    handleLogin() { this.$http.post("login", this.formLabelAlign).then(res => { const { dat ...

  6. 【NSSCTF-Round#16】 Web和Crypto详细完整WP

    每天都要加油哦!    ------2024-01-18  11:16:55 [NSSRound#16 Basic]RCE但是没有完全RCE <?php error_reporting(0); ...

  7. widows 安装docker

    1.安装docker 依次安装如下两个文件: 如启动docker报错:可以是hv没有开启,按如下方法解决 (23条消息) Windows10启动Docker报错:Hardware assisted v ...

  8. go 1.21:cmp

    标准库 cmp 原文在这里 go 1.21 新增 cmp 包提供了与有序变脸比较相关的类型和函数. Ordered 定义如下: type Ordered interface { ~int | ~int ...

  9. springboot多模块打包报错问题根因分析:Unable to find main class

    问题背景: 项目结构为springboot多模块,其中有四个模块bean.utils.user.ems,其中user和ems模块为主程序,包含启动类,其他两个模块为其服务,提供依赖 问题分析: 查看u ...

  10. 深入浅出Java多线程(一):进程与线程

    引言 大家好,我是你们的老伙计秀才. 在计算机系统的发展历程中,早期的计算机操作模式十分单一和低效.用户只能逐条输入指令,而计算机则按照接收指令的顺序逐一执行,一旦用户停止输入或进行思考,计算机会处于 ...