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

相关推荐
江畔柳前堤13 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore14 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考15 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX16 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面16 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号17 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽17 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI17 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者19 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者19 小时前
【征程6】校准量化中HistogramObserver解析
算法