
🎬 个人主页 :MSTcheng · CSDN
🌱 代码仓库 :MSTcheng · Gitee
🔥 精选专栏 : 《C语言》
《数据结构》
《算法学习》
《C++由浅入深》
💬座右铭: 路虽远行则将至,事虽难做则必成!
前言上一篇文章我们讲解了如何利用滑动窗口来解决,将x减到0的最小操作数问题,本篇文章我们继续使用滑动窗口的思想来解决水果成篮问题。
在前一篇文章中我们介绍了滑动窗口,本篇文章就不再介绍了,直接进入正题:
一、利用滑动窗口解决水果成篮问题
1.1题目展示

1.2题目示例

1.3题目解析

1.4算法原理
从题目中我们看到了最大字眼,以及我们自己总结出来找子数组,那就会想到使用滑动窗口了。

那么优化之后就是典型的滑动窗口的做法了,那么滑动窗口就分为4步:
- 进窗口,
hash[fruits[right]]++,这一步是将right下标位置的元素插入到哈希表中,并且将次数++- 判断:将
right下标位置的数依次插入到哈希表,如果哈希表长度大于2了,说明此时哈希表已经存在三种数了。(这里的哈希表使用的是unordered_map)对于map使用不熟悉的点击: 【C++STL】map / multimap 保姆级教程:从底层原理到实战应用!- 判断完后就要出窗口了,出窗口就需要
left++往后缩小窗口,而在++之前一定要确保一种类型的数要彻底被清除比如[1,1,2,2,3,3]当right走到第一个3时窗口中含有三种类型的数,此时left++要跳过两个1走到第一个2的时候窗口才合法。 而跳过两个1的方法就是将哈希表里面所存的该数的次数--,人如果减到了0就直接删除。- 更新结果,当窗口满足条件时计算子数组区间的长度即可
1.5代码编写
下面给出完整代码:
cpp
class Solution {
public:
int totalFruit(vector<int>& fruits)
{
int size=fruits.size();
//定义两个指针
int left=0,right=0;
int maxlen=0;
unordered_map<int,int> Hash;
for(right=0;right<size;right++)
{
//进入窗口 将fruits[right]位置的数放入哈希表
Hash.insert({fruits[right],0});
Hash[fruits[right]]++;
while(Hash.size()>2)
{
//出窗口 关心如何将Hash.size()调到等于2的问题
if(Hash[fruits[left]]!=0)
Hash[fruits[left]]--;
//判断当前的fruits[left]处的果树的个数是否减到0了
//如果减到0了 就直接删除这种类型的水果
if(Hash[fruits[left]]==0)
{
auto pos=Hash.find(fruits[left]);
Hash.erase(pos);
}
left++;//滑出窗口
}
//跳出循环此时窗口合法 更新结果
int currtlen=right-left+1;
maxlen=max(maxlen,currtlen);
}
if(maxlen==0)
{
//如果maxlen没有更新 那么说明只有一种类型的水果
//直接返回数组的大小
return size;
}
return maxlen;
};
三、总结
本题我们使用了滑动窗口来解决,滑动窗口的特征是:
- 两个指针都向同一个方向去运动,且指针不会回退。
- 滑动窗口的步骤就是:进窗口,判断,出窗口,更新结果这几个步骤。
什么时候该用滑动窗口?
当你看到题目包含以下关键词时,可以考虑:
1、连续(子数组、子串)。
2、求最值(最长、最短、最大和)。
3、约束条件(和等于 K、不包含重复字符)。
