算法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种元素"类问题的通用高效方法。

相关推荐
啊我不会诶1 小时前
2024北京市赛补题
c++·算法
智慧物业老杨1 小时前
物业数智化转型实战:从单一服务到综合解决方案的技术落地路径
人工智能·算法·ai
夏末蝉未鸣011 小时前
Sort-Merge Join【排序连接算法】详解(python代码实现,以FULL JOIN为例)
数据结构·算法
tjl521314_211 小时前
01C++ 分离编译与多文件编程
前端·c++·算法
_日拱一卒1 小时前
LeetCode:23合并K个升序链表
java·数据结构·算法·leetcode·链表·职场和发展
哆啦刘小洋1 小时前
【LeetCode每日一题】:2033(贪心+快速排序魔改)
算法·leetcode
WolfGang0073211 小时前
代码随想录算法训练营 Day48 | 图论 part06
算法·图论
cheems95271 小时前
[算法手记] 动态规划 ,二维费用限制背包问题如何处理
算法·动态规划
Chase_______1 小时前
LeetCode 1343 题解:定长滑动窗口经典入门题,从暴力枚举到高效优化一文搞懂
算法·leetcode·职场和发展