news 2026/4/23 18:37:30

算法题 水果成篮

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法题 水果成篮

水果成篮

问题描述

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组fruits表示,其中fruits[i]是第i棵树产生的水果种类。

你有两个篮子,每个篮子只能装单一类型的水果,但你可以选择任意两棵树开始收集水果。

你必须从每棵树(包括选择的起始树)连续地收集水果,一旦遇到第三种类型的水果,就必须停止。

返回你能收集的水果的最大数目

示例

输入:fruits=[1,2,1]输出:3解释:可以收集[1,2,1]输入:fruits=[0,1,2,2]输出:3解释:可以收集[1,2,2]输入:fruits=[1,2,3,2,2]输出:4解释:可以收集[2,3,2,2]输入:fruits=[3,3,3,1,2,1,1,2,3,3,4]输出:5解释:可以收集[1,2,1,1,2]

算法思路

滑动窗口 + 哈希表

  1. 问题转化

    • 找到最长的连续子数组,其中最多包含两种不同的元素
    • 这是一个经典的滑动窗口问题
  2. 滑动窗口策略

    • 右指针right:扩展窗口,将新水果加入篮子
    • 左指针left:当篮子中水果种类超过2种时,收缩窗口
    • 哈希表:记录当前窗口中每种水果的出现次数
  3. 窗口收缩条件

    • 当哈希表的大小 > 2 时,需要收缩左边界
    • 移除fruits[left],如果其计数变为0,从哈希表中删除
    • left++继续收缩,直到哈希表大小 ≤ 2
  4. 最大长度更新

    • 每次扩展右边界后,如果窗口有效(水果种类 ≤ 2),更新最大长度
    • 最大长度 =right - left + 1

代码实现

方法一:滑动窗口 + 哈希表

importjava.util.*;classSolution{/** * 水果成篮 - 滑动窗口 * * @param fruits 水果类型数组 * @return 能收集的最大水果数目 * * 算法思路: * 1. 使用滑动窗口维护最多包含2种水果的连续子数组 * 2. 哈希表记录当前窗口中每种水果的计数 * 3. 当水果种类超过2种时,收缩左边界 */publicinttotalFruit(int[]fruits){Map<Integer,Integer>fruitCount=newHashMap<>();intleft=0;intmaxFruits=0;// 右指针扩展窗口for(intright=0;right<fruits.length;right++){// 将当前水果加入窗口fruitCount.put(fruits[right],fruitCount.getOrDefault(fruits[right],0)+1);// 当水果种类超过2种时,收缩左边界while(fruitCount.size()>2){intleftFruit=fruits[left];fruitCount.put(leftFruit,fruitCount.get(leftFruit)-1);// 如果某种水果计数为0,从哈希表中移除if(fruitCount.get(leftFruit)==0){fruitCount.remove(leftFruit);}left++;}// 更新最大水果数目maxFruits=Math.max(maxFruits,right-left+1);}returnmaxFruits;}}

算法分析

  • 时间复杂度:O(n)

    • 每个元素最多被访问两次(右指针和左指针各一次)
    • 哈希表操作为 O(1)
  • 空间复杂度:O(1)

    • 哈希表最多存储3个键值对(收缩前)

算法过程

1:fruits = [1,2,1]

滑动窗口过程

初始: left=0, maxFruits=0, fruitCount={} right=0: fruits[0]=1 - fruitCount={1:1} - maxFruits = max(0, 0-0+1) = 1 right=1: fruits[1]=2 - fruitCount={1:1, 2:1} - maxFruits = max(1, 1-0+1) = 2 right=2: fruits[2]=1 - fruitCount={1:2, 2:1} - maxFruits = max(2, 2-0+1) = 3 返回 3

2:fruits = [3,3,3,1,2,1,1,2,3,3,4]

窗口扩展到 [3,3,3,1] → 种类=2,长度=4 继续扩展到 [3,3,3,1,2] → 种类=3,需要收缩 收缩过程: - 移除fruits[0]=3 → {3:2, 1:1, 2:1} - 移除fruits[1]=3 → {3:1, 1:1, 2:1} - 移除fruits[2]=3 → {1:1, 2:1},left=3 窗口变为 [1,2],继续扩展... 最终找到 [1,2,1,1,2],长度=5

3:fruits = [1,2,3,2,2]

[1] → len=1 [1,2] → len=2 [1,2,3] → 种类=3,收缩到 [2,3] → len=2 [2,3,2] → len=3 [2,3,2,2] → len=4 最大长度=4

测试用例

importjava.util.*;publicclassTest{publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:标准示例int[]fruits1={1,2,1};System.out.println("Test 1: "+solution.totalFruit(fruits1));// 3// 测试用例2:需要收缩窗口int[]fruits2={0,1,2,2};System.out.println("Test 2: "+solution.totalFruit(fruits2));// 3// 测试用例3:中间有最长序列int[]fruits3={1,2,3,2,2};System.out.println("Test 3: "+solution.totalFruit(fruits3));// 4// 测试用例4:复杂情况int[]fruits4={3,3,3,1,2,1,1,2,3,3,4};System.out.println("Test 4: "+solution.totalFruit(fruits4));// 5// 测试用例5:所有相同int[]fruits5={1,1,1,1,1};System.out.println("Test 5: "+solution.totalFruit(fruits5));// 5// 测试用例6:两种交替int[]fruits6={1,2,1,2,1,2};System.out.println("Test 6: "+solution.totalFruit(fruits6));// 6// 测试用例7:单个元素int[]fruits7={1};System.out.println("Test 7: "+solution.totalFruit(fruits7));// 1// 测试用例8:两个元素int[]fruits8={1,2};System.out.println("Test 8: "+solution.totalFruit(fruits8));// 2// 测试用例9:三种连续int[]fruits9={1,2,3};System.out.println("Test 9: "+solution.totalFruit(fruits9));// 2// 测试用例10:大数组int[]fruits10=newint[40000];Arrays.fill(fruits10,1);fruits10[20000]=2;fruits10[30000]=3;System.out.println("Test 10: "+solution.totalFruit(fruits10));// 20001// 测试用例11:边界值int[]fruits11={0,1,0,1,0,1,0,1,0,1,2};System.out.println("Test 11: "+solution.totalFruit(fruits11));// 10// 测试用例12:从后往前的最长序列int[]fruits12={1,2,1,1,2,2,2,2,2};System.out.println("Test 12: "+solution.totalFruit(fruits12));// 9}}

关键点

  1. 滑动窗口

    • 右指针不断扩展,左指针在必要时收缩
    • 保证窗口内最多包含2种水果
  2. 哈希表

    • 记录当前窗口中每种水果的数量
    • 通过大小判断是否超过2种
    • 通过计数为0时移除键来准确维护种类数
  3. 边界条件处理

    • 数组长度 ≤ 2 时直接返回长度
    • 空数组

常见问题

  1. 为什么不用Set而用Map?

    • Set只能记录种类,无法记录每种水果的数量
    • 需要知道何时可以安全移除某种水果(计数为0时)
  2. 如果篮子数量不是2而是k?

    • 算法逻辑相同,只需要将条件> 2改为> k
    • 这是滑动窗口解决"最多k种元素"问题的通用模式
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:31:48

AI艺术展:用Z-Image-Turbo快速生成系列主题作品的策展指南

AI艺术展&#xff1a;用Z-Image-Turbo快速生成系列主题作品的策展指南 如果你正在筹备一场AI艺术展览&#xff0c;需要批量生成风格统一的作品&#xff0c;Z-Image-Turbo可能是你的理想选择。这款基于通义造相技术的文生图模型&#xff0c;能够快速产出高质量图像&#xff0c;特…

作者头像 李华
网站建设 2026/4/23 12:31:39

【std::map】遍历方式汇总

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录1. 普通迭代器遍历&#xff08;最基础方式&#xff09;2. const迭代器遍历&#xff08;只读场景&#xff09;3. 反向迭代器遍历&#xff08;逆序遍历&#xff09;4. …

作者头像 李华
网站建设 2026/4/23 4:02:54

从图片到视频:基于阿里通义Z-Image-Turbo WebUI的动态内容生成

从图片到视频&#xff1a;基于阿里通义Z-Image-Turbo WebUI的动态内容生成 作为一名视频制作人&#xff0c;你是否遇到过这样的困扰&#xff1a;现有的AI工具大多只能生成静态图像&#xff0c;而你想要的是让这些图像动起来&#xff0c;变成生动的动画效果&#xff1f;今天我要…

作者头像 李华
网站建设 2026/4/23 11:21:45

周末项目:用阿里通义Z-Image-Turbo WebUI打造你的个人AI画室

周末项目&#xff1a;用阿里通义Z-Image-Turbo WebUI打造你的个人AI画室 作为一名业余插画师&#xff0c;你是否曾想过借助AI的力量来激发创作灵感&#xff0c;却又被复杂的安装配置劝退&#xff1f;阿里通义Z-Image-Turbo WebUI正是为这类需求而生的开箱即用解决方案。它基于S…

作者头像 李华
网站建设 2026/4/23 11:19:07

阿里通义Z-Image-Turbo WebUI批量处理教程:高效生成海量图像

阿里通义Z-Image-Turbo WebUI批量处理教程&#xff1a;高效生成海量图像 如果你是一位电商运营人员&#xff0c;需要为数千种商品生成展示图片&#xff0c;手动操作效率极低。那么阿里通义Z-Image-Turbo WebUI的批量处理功能就是你的救星。本文将详细介绍如何使用这个强大的AI工…

作者头像 李华