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

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开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
