【滑动窗口】篮里到底能装 “几个水果” 呢?

Problem: 904. 水果成篮
文章目录
- 题目分析
- 算法原理分析
- 暴力枚举 + 哈希表
- 滑动窗口优化
- 数组再度优化
- 复杂度
- Code
题目分析
首先我们来分析一下本题的思路
- 首先我们通过题目的描述来理解一下其要表达的含义,题目给到我们一个
fruit数组,里面存放的是每棵树上水果的数量。当我们拿着两个篮子去采摘水果的时候,可以选择任意一颗树开始采摘 - 虽然篮子里面只能装一种水果,即两个篮子只能有两种水果,但是每种水果所装的个数是不受限制的,所以只要水果的种类不超过两种即可

- 我们再来仔细看一下示例,比如这个示例1,
{1, 2, 1}指的就是第一棵树上有一个【1号水果】,第二棵树上有一个【2号水果】,第三棵树上有一个【1号水果】。所以若是我们从第一棵开始采摘的话,可以采摘到 2个1号水果和1个2号水果 - 看到示例2,第一棵树上有一个【0号水果】,第二棵树上有一个【1号水果】,第三棵树上有一个【2号水果】,第三棵树上也有一个【2号水果】。
- 那若是我们从第一棵树开始采摘的话,摘完【0号】与【1号】水果就必须停下来了
- 若是我们从从第二棵树开始采摘的话,可以摘到【1号】与【2号】水果,并且【2号】水果可以采摘到两个,总水果树有3个,因此我们从第二棵树开始采摘最好
- 相信在看了上面的这些描述之后,读者应该是很清楚了,再来举一个例子
{1, 1, 1, 1, 1, 1},对于这个来说的话我们可以知道所摘的水果种类为1个,数量为6个

💬 那么本题我们就转换为了:找出一个最长的子数组长度,子数组中不超过两种类型的水果
算法原理分析
接下去我们就来分析一下本题的算法原理
暴力枚举 + 哈希表
- 首先最先相当的一定是暴力枚举,从第一个数开始往后进行枚举,以此类推,找到符合条件且长度最长的那一个。将做遍历到的加入到哈希表中,在遍历的过程中逐步进行判断即可
- 对于暴力解法的代码这里就不展示了,读者可以自己尝试着去写写看

滑动窗口优化
- 我们主要还是来讲一讲有关如何使用【滑动窗口】去做优化的事情,那对于滑动窗口而言我们知道是基于『双指针』的,所以在这里我们会需要有一个
left指针和一个right指针,当这个right指针在向后移动的时候,当其无法在继续后移的时候表示[left, right]这段区间内的水果数量已经到达②了,此时我们要考虑去做【出窗口】的操作

- 那这个时候我们让
left指针向右移动一格,那此时读者可以思考一下当前的kinds会出现什么样的变化?

- 在下面我列举出了两种,一个是 kinds不变的情况,因为其在后移的过程中,所取消掉的那一个水果的种类可能在
[left, right]这个区间中还存在着这个种类的水果 - 第二个则是 kinds变小的情况,很好理解,若是在
[left, right]区间中不包含了去除掉的这种水果的话,说明种类就会减少

- 与之相对应的我们要给出
right指针相应的变化情况,若是kinds不做变化的话,right也无需去变化,因为再去右移的话可能会增加水果的种类;若是kinds变小的话,那么right就可以右移了,此时水果的种类就可以增加上去
那接下去呢,就让我们来看看,算法的执行过程是怎样的
- 在这里,我们的哈希表中所存的数据种类有两个,一个是 当前的水果种类,另一个呢则是 这个水果所对应的数量。
- 所以当我们使用右指针
right在进行遍历的时候,其所对应的个数就++,那当这个数量大于2时就开始出窗口,所对应的则是left左指针所指向的水果个数,但是呢这不是随便减的,当其减到【0】的时候,就要考虑从这个哈希表中删除掉这个相对应的水果了。 - 最后当出完窗口后我们要做的就是去更新这个最长的结果

好,以上就是有关【滑动窗口】相关的算法原理分析,详情代码见【Code】
💬 那有同学问:为何不直接讲滑动窗口相关的算法呢,而是每次都要讲一下暴力的解法,这不是多此一举吗?
- 同学,你应该要明白,我们在笔试面试时做算法题的时候,不是一看到一道题的时候就会想到它到底需要使用什么算法与数据结构,一般在拿到一道题的时候我们一般都会先去考虑暴力的解法。在思考一段时间之后才会去思考其是都可以一些算法来进行解决,我们平常在刷题的过程中,重要的不是你马上就能想到这个算法,我们更加关注的是这个解题的过程,大家在练习算法题的时候一定要格外注意
数组再度优化
有读者一定会疑惑,已经使用【滑动窗口】去做了优化为什么还要再去优化呢?我们可以来看看滑动窗口的代码提交之后的结果
- 可以看到效率并不是很高,原因其实就在于我们在频繁地去出入窗口

💬 那怎么去做一个优化呢?
- 我们再来观察一下题目给到我们的提示,这个
fruit数组最大的个数为 $ 10^5 $,那我们其实可以不用使用哈希表去存储,而是直接利用【数组】去进行存放,因为对于数组的每个元素来说其实就是一种映射,和哈希表其实是差不多的原理

- 我们可以选择直接将数组的大小定为这个大小,并且呢我们需要在循环中放一个
kinds变量用于代替哈希表的个数统计
int hash[100001] = { 0 };
for(int left = 0, right = 0, kinds = 0; right < n; ++right)
- 那么当我们在碰到水果的个数减到0的时候,不去使用
erase,而是直接kinds--去控制当前窗口中的水果个数
if(hash[fruits[left]] == 0)// hash.erase(fruits[left]);kinds--;
- 那么当我们一进循环遍历的时候,也需要去做一个判断,若是当前遍历到的这个水果的个数为0的话,就将
kinds的个数进行一个累加
// 一进来判断发现水果的种类为0的话,则水果种类增加一种
if(hash[fruits[right]] == 0) kinds++;
- 那么在最后当我们中途去判断这个水果个数的时候,只需要对这个
kinds做出判断即可
fi(kinds > 2)
💬 具体代码可以参照【Code】部分,我们来看到提交之后的执行结果可以观察到性能确实得到了大幅度的提升

复杂度
接下去我们来分析一下时间复杂度
- 时间复杂度:
首先是对于时间复杂度而言,【滑动窗口】部分的代码, 我们使用
left和right双指针去遍历查找整个数组, 并且在查找的过程中遇到水果数量 > 2需要去做出窗口的操作,因为erase()的复杂度为 O ( n ) O(n) O(n), 所以在最坏的情况下复杂度可以到达 O ( n 2 ) O(n^2) O(n2)
而对于数组优化来说, 虽免去了哈希表,没了计数的功效。但是我们只是去做了遍历的操作,中间循环的过程使用的是
kinds作的标记操作,不涉及erase(),因此最坏的复杂度因为 O ( n ) O(n) O(n)
- 空间复杂度:
对于空间复杂度来说,两种优化的方法并没有涉及额外空间的申请, 所以空间复杂度即为: O ( 1 ) O(1) O(1)
Code
接下去是代码部分
- 首先的话是有关【滑动窗口】优化的代码
class Solution {
public:int totalFruit(vector<int>& fruits) {int n = fruits.size();unordered_map<int, int>hash;int max_len = INT_MIN;for(int left = 0, right = 0; right < n; ++right){// 1.进窗口hash[fruits[right]]++;// 当水果的种类多于2种的时候,开始出窗口if(hash.size() > 2){// 2.出窗口【此时left不能后移,因此要删除该水果】hash[fruits[left]]--;// 如果当前水果种类的数量到0的话,将其从哈希表中删除if(hash[fruits[left]] == 0)hash.erase(fruits[left]);left++;}// 更新结果max_len = max(max_len, right - left + 1);}return max_len == INT_MIN ? 0 : max_len;}
};
- 然后的话是有关【数组优化】的代码
class Solution {
public:int totalFruit(vector<int>& fruits) {int n = fruits.size();//unordered_map<int, int> hash;int hash[100001] = { 0 };int max_len = INT_MIN;for(int left = 0, right = 0, kinds = 0; right < n; ++right){// 一进来判断发现水果的种类为0的话,则水果种类增加一种if(hash[fruits[right]] == 0) kinds++;// 1.进窗口hash[fruits[right]]++;// 判断当前哈希表中水果的种类是否超过两种if(kinds > 2){// 2.出窗口hash[fruits[left]]--;// 如果在出窗口之后当前水果的数量为0的话,则从哈希表中删除该水果if(hash[fruits[left]] == 0)// hash.erase(fruits[left]);kinds--;left++;}// 3.更新最大长度max_len = max(max_len, right - left + 1);}return max_len == INT_MIN ? 0 : max_len;}
};

相关文章:
【滑动窗口】篮里到底能装 “几个水果” 呢?
Problem: 904. 水果成篮 文章目录 题目分析算法原理分析暴力枚举 哈希表滑动窗口优化数组再度优化 复杂度Code 题目分析 首先我们来分析一下本题的思路 首先我们通过题目的描述来理解一下其要表达的含义,题目给到我们一个fruit数组,里面存放的是每棵树上…...
newstarctf2022week2
Word-For-You(2 Gen) 和week1 的界面一样不过当时我写题的时候出了个小插曲 连接 MySQL 失败: Access denied for user rootlocalhost 这句话印在了背景,后来再进就没了,我猜测是报错注入 想办法传参 可以看到一个name2,试着传参 发现有回显三个字段…...
集群调度-01
目录 1、调度约束 2、Pod 是 Kubernetes 的基础单元,Pod 启动典型创建过程如下 2.1 工作机制 **** 2.2 调度过程 *** 2.3 Predicate 有一系列的常见的算法可以使用: ** 2.4 指定调度节点 1、调度约束 Kubernetes 是通过 List-Watch **…...
【软件工程】金管局计算机岗位——软件测试的分类(⭐⭐⭐⭐)
软件工程 软件测试的分类从是否关心软件内部结构和具体实现的角度划(⭐⭐⭐⭐)从是否执行代码角度划分(⭐⭐)从软件开发的过程按阶段划分(⭐⭐⭐⭐) 软件测试的分类 考点导读: 软件测试是软件工…...
Halcon WPF 开发学习笔记(1):Hello World小程序
文章目录 文章专栏视频链接Hello World训练图片训练目的 开始训练图像预处理导入图像三通道处理调用算子通道选取 滤波什么是好的滤波 增加对比度 区域选取阈值处理算子参数选择运行结果(红色为选择区域) 区域分割运行结果 特征筛选参数代码第二次,面积筛选 画选中十…...
pix2tex - LaTeX OCR 安装使用记录
系列文章目录 文章目录 系列文章目录前言一、安装二、使用三、少侠请留步,点赞、收藏、关注 前言 项目地址:这儿 一、安装 版本要求 Python: 3.7 PyTorch: >1.7.1 安装:pip install "pix2tex[gui]" 注意:Pyside6…...
前端框架Vue学习 ——(四)Axios
文章目录 Axios 介绍Axios 入门Vue项目中使用 Axios Axios 介绍 介绍: Axios 对原生的 Ajax 进行了封装,简化书写,快速开发。(异步请求) 官网: https://www.axios-http.cn/ 官网介绍:Axios 是一个基于 promise 网络请…...
将json数据导入到ES集群——解决方案对比填坑日记
需求 将写好的json数据。导入到es集群 数据说明 文件JSON数据,一行一个JSON。 {"id":"d2716ae8fba4e026c4bd9445c3f49e2c","lang":"zh","title":"吉美旅馆","content":"吉美..."}…...
C语言----------#pragma预处理分析
一、#pragma预处理分析 1、#pragma是编译器指示字,用于指示编译器完成一些特定的动作; 2、#pragma所定义的很多指示字是编译器和操作系统特有的; 3、#pragma在不同的编译器间是不可移植的: 预处理器将忽略它不认识的#pragma指…...
数据库中的时间django转换成None
原因 数据库中使用的是datetime[64] 的格式。精确的毫秒了。django默认的使用的是datetime.datetime.fromisoformat转换的。转换不了 使用原生查找 for raw in StockNominate.objects.raw("select id,code,strftime(%Y-%m-%d,date) as date from table_name; "):pr…...
八种流行的网络协议
1、HTTP(超文本传输协议),HTTP 是一种用于获取 HTML 文档等资源的协议。它是 Web 上任何数据交换的基础,是一种客户端 - 服务器协议。 2、HTTP/3,HTTP/3 是 HTTP 的下一个重大修订版。它运行在 QUIC 上,QU…...
Qwt QwtKnob绘制旋钮
1.简介 QwtKnob是Qwt库中的一个类,用于绘制一个旋钮样式的仪表盘。它继承QwtAbstractSlider类,提供了一些额外的功能和样式,用于旋转和选择值。 以下是类继承关系: 2.常用方法 旋钮(Knob)相关的属性和方法…...
docker部署elk
目录 前言 一、创建程序工作路径 二、创建私有网络 三、部署elasticsearch 1.先搜速后下载 2.创建一个基础的容器(此步骤是为了拷贝容器里的文件) 3.拷贝文件到宿主机 3.1进入容器 3.2拷贝并授权 3.3删除基础容器 4.创建容器 5.访问9200测试 …...
护网蓝队初级面试题摘录(下)
小王学习录 1.设备误报如何处理?2.讲一下TOP10都有哪些3.SQL注入的原理和漏洞产生的原因?4.SQL注入的类型盲注类型: 5.简单讲一下防范SQL注入的方法和原理6.SQL注入有哪些绕过姿势?7.SQL注入攻击有哪些危害?6.XSS&…...
通过51单片机控制SG90舵机按角度正反转转动
一、前言 本文介绍如何通过51单片机控制SG90舵机实现角度的正反转转动。SG90舵机是一种常用的微型舵机,具有体积小、重量轻、结构简单等特点,被广泛应用于机器人、遥控模型和各种自动控制系统中。 使用51单片机(STC89C52)作为控…...
uniapp写一个计算器用于记账(微信小程序,APP)
提要:自己用uniapp写了一个记账小程序(目前是小程序),写到计算器部分,在网上找了别人写的计算器,大多数逻辑都是最简单的,都不能满足一个记账计算器的基本逻辑。与其在网上找来找去,…...
前端的几种网络请求方式
网络请求 node编写接口 这里用到的几个包的作用 express:基于 Node.js 平台,快速、开放、极简的 Web 开发框架,官网:https://www.expressjs.com.cn/cors:用来解决跨域问题body-parser:可以通过 req.body…...
Kubernetes技术与架构-存储 4
如上所示,Kubernetes集群支持动态申请存储资源,即集群管理员可以按照实际的需求动态地申请存储资源,集群管理员需要事先定义一个或者多个StorageClass存储类型的资源,Pod中的容器实例直接引用事先定义的StorageClass存储类型的资源…...
jbase编译与部署的优化
上一篇的演示只是涉及自动编译业务脚本。演示时候工程编译是超级慢的。因为把静态资源放在了Web工程下,每次编译都要拷贝,运行起码是1分钟,不能忍受,为此思考工程结构改解决这个问题,顺带方便开发的发布。运行WebLoade…...
Filter 和 Listener
Filter 表示过滤器。是JavaWeb三大组件(Servlet、Filter、Listener)之一。 过滤器可以把对资源的请求 拦截 下来。浏览器可以访问服务器上所有的资源,而在访问到这些资源之前可以使用过滤器拦截下来,也就是说在访问资源之前会先经…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
AWSLambda之设置时区
目标 希望Lambda运行的时区是东八区。 解决 只需要设置lambda的环境变量TZ为东八区时区即可,即Asia/Shanghai。 参考 使用 Lambda 环境变量...
