leetcode-904 水果成篮

题目

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

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从每棵树(包括开始采摘的树)上恰好摘一个水果。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的最大数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

提示:

  • 1 <= fruits.length <= 105
  • 0 <= fruits[i] < fruits.length

分析

  1. 输入的 fruits 数组,表示每棵树上的水果种类,数组索引表示树的顺序,数组值表示树上的水果种类;
  2. 共有两个篮子,且每个篮子只能装一种水果,表示总共水果种类不能超过两种;
  3. 必须从某棵树开始,连续采摘直到不符合的水果类型才停止,表示求的实际是 fruits 的一个元素种类不超过 2 的最长子数组,此处的第三个不同水果种类,即为停止采摘的条件;
  4. 综上,在数组中查找最长连续子数组,且子数组中元素种类不超过 2 个,适合采用滑动窗口法求解。

思路

  1. 定义滑动窗口左右边界 left 和 right,初始值均为 0,表示从 fruits 数组第一个元素开始采摘;
  2. 定义篮子 basket,用于存放采摘的水果种类,这里可以用哈希表表示,水果种类为 key,水果数量为 value;
  3. 定义采摘的最大水果量 maxFruits,初始值为 0,用来存放窗口滑动过程中最大水果量;
  4. 边界处理:如果一开始 fruits 长度为 0 ,表示没有水果,直接返回 0;
  5. 开始采摘,右边界 right 从索引 0 开始递增,此处使用循环结构表示;
  6. 进行过程判断,如果采摘水果在篮子中不存在,basket 中加入该水果,初始值为 1,如果已存在,则该水果数量加 1;
  7. 加入水果后,如果篮子水果种类超过 2 种,则对左边界 left 进行收缩,此处采用内循环表示,每次数量减一,当数量为 0 时,则从篮子里删除该水果,即 basket 删除该水果的 key,直到篮子中水果种类不超过 2 种;
  8. 如果加入水果后种类未超,则更新最大水果数 maxFruits,maxFruits 取 maxFruits 与 right-left+1(表示当前窗口水果数量)中的较大值,然后右边界 right 加 1,表示窗口前移一位;
  9. 重复以上步骤,直到右边界 right 超出 fruits 数组长度,此时采摘结束,返回最大水果数 maxFruits。

go 实现示例

func totalFruit(fruits []int) int {

    // 定义滑动窗口左右边界
	left, right := 0, 0

	// 定义篮子,用于存放水果种类
	basket := make(map[int]int)

	// 定义最大水果数
	maxFruit := 0

	// 如果fruits为空,表示没有水果,直接返回0
	if len(fruits) == 0 {
		return 0
	}

	// 当右边界小于fruits长度时,遍历fruits
	for right < len(fruits) {

		// 右边界水果种类放入篮子
		if _, exists := basket[fruits[right]]; exists {
			basket[fruits[right]]++
		} else {
			basket[fruits[right]] = 1
		}

		// 如果篮子中水果种类大于2,移动左边界,直到篮子中水果种类小于等于2
		for len(basket) > 2 {
			basket[fruits[left]]--
			if basket[fruits[left]] == 0 {
				delete(basket, fruits[left])
			}
			left++
		}

		// 更新最大水果数
		maxFruit = max(maxFruit, right-left+1)

		// 右指针向前移动
		right++
	}

	return maxFruit
}
posted @ 2025-08-05 23:17  505donkey  阅读(29)  评论(0)    收藏  举报