算法13,滑动窗口,水果成篮

复制代码
class Solution {
    public int totalFruit(int[] f) {
         Map<Integer, Integer> hash = new HashMap<>();
        int ret=0;
        for(int left =0,right=0;right<f.length;right++) {
            int in=f[right];
            hash.put(in,hash.getOrDefault(in,0)+1);
            while(hash.size()>2) {
                int out=f[left];
                hash.put(out,hash.get(out)-1);
                if(hash.get(out)==0) {
                    hash.remove(out);
                }
                left++;
            }
            ret=Math.max(ret,right-left+1);
        }
        return ret;
    }
}

要解决"滑动窗口(水果成篮)"问题(对应在数组中找最多包含2种不同元素的最长连续子数组长度),可通过「滑动窗口 + 哈希表」思路高效求解,以下是分步讲解:

步骤1:明确问题本质

给定整数数组 fruits(每个元素代表一种水果),仅有2个篮子(即子数组中最多包含2种不同水果 ),需找到满足条件的最长连续子数组长度

步骤2:暴力法思路(辅助理解,非最优)

枚举所有可能的连续子数组,统计子数组内不同水果的数量:

  • 若不同水果数 ≤ 2,更新"最长长度";

  • 时间复杂度 O(n2)(n为数组长度),当 n较大时效率极低,因此需优化。

步骤3:滑动窗口 + 哈希表(最优解,时间复杂度 O(n))

通过双指针(左指针 left、右指针 right 维护"当前窗口",用哈希表记录窗口内各水果的出现次数,确保窗口内始终最多有2种水果。具体流程:

  1. 初始化变量

    • 左指针 left = 0

    • 结果变量 maxLen = 0(记录最长子数组长度);

    • 哈希表 hash(键为水果类型,值为该类型在窗口内的出现次数)。

  2. 右指针遍历数组

    右指针 right0遍历到数组末尾,对每个 fruits[right]执行:

    • fruits[right]加入哈希表:若已存在则计数+1,否则初始化为1。
  3. 收缩左指针(保证窗口内≤2种水果)

    当哈希表的大小(即不同水果的数量)> 2时,需移动左指针缩小窗口:

    • 取出 fruits[left]在哈希表中的计数,减1;

    • 若计数减为0,从哈希表中删除该水果(避免干扰后续判断);

    • 左指针 left++,继续检查哈希表大小是否仍>2,直到≤2为止。

  4. 更新最长长度

    每次右指针移动后,计算当前窗口长度 right - left + 1,并与 maxLen比较,取较大值更新 maxLen

  5. 返回结果

    遍历结束后,maxLen即为满足条件的最长子数组长度。

代码逻辑参考(以Java为例)

复制代码
public int totalFruit(int[] fruits) {
    Map<Integer, Integer> hash = new HashMap<>();
    int left = 0, maxLen = 0;
    for (int right = 0; right < fruits.length; right++) {
        // 右指针加入当前水果,更新哈希表计数
        int curFruit = fruits[right];
        hash.put(curFruit, hash.getOrDefault(curFruit, 0) + 1);
        
        // 若哈希表大小>2,收缩左指针
        while (hash.size() > 2) {
            int leftFruit = fruits[left];
            // 左指针水果计数减1
            hash.put(leftFruit, hash.get(leftFruit) - 1);
            // 若计数为0,从哈希表删除
            if (hash.get(leftFruit) == 0) {
                hash.remove(leftFruit);
            }
            left++; // 左指针右移
        }
        
        // 更新最长子数组长度
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

核心思想总结

滑动窗口通过双指针动态调整窗口范围,哈希表高效维护窗口内元素的"种类与数量",确保算法在 O(n)时间复杂度内完成(每个元素仅被左右指针各访问一次),是处理"子数组最多包含K种元素"类问题的通用高效方法。

相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼2 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光2 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark2 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her12 天前
并查集-听课笔记
笔记·算法·并查集
码流子2 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven2 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark2 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218612 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法