首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【优选算法必刷100题】第013题(同向双指针:滑动窗口算法):水果成篮问题

【优选算法必刷100题】第013题(同向双指针:滑动窗口算法):水果成篮问题

作者头像
艾莉丝努力练剑
发布2025-11-18 13:21:13
发布2025-11-18 13:21:13
860
举报
文章被收录于专栏:C / C++C / C++

013 水果成篮

力扣链接:904. 水果成篮

力扣题解链接:滑动窗口+数组模拟哈希表解决

题目描述:

1.1 解法:滑动窗口——算法思路

研究的对象是一段连续的区间,可以使用「滑动窗口」思想来解决问题。

让滑动窗口满足:窗口内水果的种类只有两种。

做法:右端水果进入窗口的时候,用哈希表统计这个水果的频次。这个水果进来后,判断哈希表的

大小——

(1)如果大小超过2:说明窗口内水果种类超过了两种。那么就从左侧开始依次将水果划出窗口,直到哈希表的大小小于等于2,然后更新结果; (2)如果没有超过2,说明当前窗口内水果的种类不超过两种,直接更新结果ret。

1.2 算法流程

1、初始化哈希表hash来统计窗口内水果的种类和数量;

2、初始化变量:左右指针left=0,right=0,记录结果的变量ret=0;

3、当right小于数组大小的时候,一直执行下列循环——

(1)将当前水果放入哈希表中;

(2)判断当前水果进来后,哈希表的大小:

[1] 如果超过2—— 1)将左侧元素滑出窗口,并且在哈希表中将该元素的频次减一; 2)如果这个元素的频次减一之后变成了0,就把该元素从哈希表中删除; 3)重复上述两个过程,直到哈希表中的大小不超过2;

(3)更新结果 ret

(4)right++,让下一个元素进入窗口;

4、循环结束后,ret存的就是最终结果。

1.3 算法实现

1.3.1 第一次猛攻:失败

代码演示如下——

代码语言:javascript
复制
//自己实现,战败
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        //hash表
        unordered_map<int, int> hash;
        //返回结果
        int ret = 0;
        //统计窗口内的水果类型和单一水果类型对应的水果数量
        for (int left = 0, right = 0; right < fruits.size(); right++)
        {
            hash[fruits[right]]++;//进窗口
            if (hash.size() > 2)
                hash[fruits[left]]--;//出窗口
            //小细节
            if (hash[fruits[right]] == 0)
                erase(hash[fruits[right]]);
            fruits[left]++;//left可以继续右移
            //更新结果
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

时间复杂度:O(n),空间复杂度:O(1)。

1.3.2 使用容器实现

代码演示如下——

代码语言:javascript
复制
//还是可以再优化,hash表频繁插入删除,时间复杂度虽然好,但还是比较耗时的
//可以进行小优化,针对的就是hash表
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        //hash表
        unordered_map<int, int> hash;
        //返回结果
        int ret = 0;
        //统计窗口内的水果类型和单一水果类型对应的水果数量
        for (int left = 0, right = 0; right < fruits.size(); right++)
        {
            hash[fruits[right]]++;//进窗口
            while (hash.size() > 2)
            {
                //出窗口
                hash[fruits[left]]--;
                //小细节
                if (hash[fruits[left]] == 0)
                    hash.erase(fruits[left]);
                left++;//left可以继续右移
            }
            //更新结果
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

时间复杂度:O(n),空间复杂度:O(1)。

这里虽然时间复杂度良好,但是这种写法频繁地在hash表插入/删除一个元素,虽然时间复杂度是O(N),但是还是比较耗时的。

1.3.3 优化:使用数组模拟哈希表——投机取巧

数量级是10^5,我们可以直接用数组模拟哈希表——

代码演示如下——

代码语言:javascript
复制
//优化了hash表之后,提高效率的一种做法
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        //hash表
        unordered_map<int, int> hash;
        //返回结果
        int ret = 0;
        //统计窗口内的水果类型和单一水果类型对应的水果数量
        for (int left = 0, right = 0; right < fruits.size(); right++)
        {
            hash[fruits[right]]++;//进窗口
            while (hash.size() > 2)
            {
                //出窗口
                hash[fruits[left]]--;
                //小细节
                if (hash[fruits[left]] == 0)
                    hash.erase(fruits[left]);
                left++;//left可以继续右移
            }
            //更新结果
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

时间复杂度:O(n),空间复杂度:O(1)。

现在耗时的情况就已经优化不少了。

1.3.4 经验总结

经验总结:如果数据范围有限,可以直接搞一个数组来模拟哈希表。

1.4 博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己推导很重要!


结尾

往期回顾:

【优选算法必刷100题】第011~012题(同向双指针:滑动窗口算法):最大连续1的个数 III、将 x 减到 0 的最小操作数

结语:看到这里,不要忘记给博主来个“一键四连”哦!

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 013 水果成篮
    • 1.1 解法:滑动窗口——算法思路
    • 1.2 算法流程
    • 1.3 算法实现
      • 1.3.1 第一次猛攻:失败
      • 1.3.2 使用容器实现
      • 1.3.3 优化:使用数组模拟哈希表——投机取巧
      • 1.3.4 经验总结
    • 1.4 博主手记
  • 结尾
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档