一、题目
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits
表示,其中 fruits[i]
是第 i
棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
- • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits
,返回你可以收集的水果的 最大 数目。
二、示例
2.1> 示例 1:
【输入】fruits = [1,2,1] 【输出】3 【解释】可以采摘全部 3 棵树。
2.2> 示例 2:
【输入】fruits = [0,1,2,2] 【输出】3 【解释】可以采摘 [1,2,2] 这三棵树。如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
2.3> 示例 3:
【输入】fruits = [1,2,3,2,2] 【输出】4 【解释】可以采摘 [2,3,2,2] 这四棵树。如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。
2.4> 示例 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
三、解题思路
根据题目描述,我们只可以拿两种类型的水果,并且获取的顺序是按照数组fruits的顺序从左向右的,那么我们可以选择采用滑动窗口的方式对窗口内两种类型的水果数量进行计算,并且针对每个窗口中的水果数量进行计算,最终选取最大值返回即可。
我们以下图中fruits = [3,3,3,1,2,1,1,2,3,3,4]
为例,首先我们需要如下几个参数:
startIndex:表示窗口的起点。 diffIndex:每当发现相邻两个水果不同,则将其指向发生不同的那个水果,当遍历发现有第三种水果的时候,用于将其作为新窗口的起点。 pickRecords:用于记录当前窗口内选中的水果(下图没有画),默认未选中为0,选中为1; pickNums:用于记录当前窗口内,已经选中的水果种类数量。 curFruit:用于记录当前选中的苹果类型,当发现curFruit与fruits[i]不同时,diffIndex = fruits[i]。
我们从头开始遍历,遍历指针i
,每当发现遍历到的这个水果种类fruits[i]与curFruit不同时,就说明我们拿到了新的品种,那么pickNums加1,当超过2种的时候,我们就通过i-startIndex
对窗口内的水果数量进行计算,然后移动窗口,将新窗口的起点设定为diffIndex
指向的位置,然后继续遍历水果,以此类推进行计算。具体操作如下图所示,此处就不赘述了:
四、代码实现
代码语言:javascript复制class Solution {
public int totalFruit(int[] fruits) {
int[] pickRecords = new int[fruits.length];
int result = 0, startIndex = 0, diffIndex = 0, pickNums = 0, curFruit = 0;
for (int i = 0; i < fruits.length; i ) {
if (pickRecords[fruits[i]] == 0) {
if (pickNums == 2) {
result = Math.max(result, i - startIndex);
pickRecords[fruits[diffIndex - 1]] = 0; // 将水果设置为“未被选择”
startIndex = diffIndex; // 记录“窗口”的开始index
pickNums--; // 已选择的水果种类-1
}
pickNums ; // 已选择的水果种类 1
pickRecords[fruits[i]] = 1; // 将水果设置为“被选择”
}
if (curFruit != fruits[i]) {
curFruit = fruits[i]; // 当前水果类型
diffIndex = i; // 记录水果类型变换时的index
}
}
return Math.max(result, fruits.length - startIndex);
}
}