题目链接: leetcode.cn/problems/fr…
题目描述:
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 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 <= 1050 <= fruits[i] < fruits.length
题目解析
给了一个整数数组 fruits ,fruits[i] 表示第 i 棵树上的水果种类。并且我们有两个篮子,每个篮子只能装一种水果,容量无限。我们可以从任意一个地方进行采摘,但是只要遇到第三种水果,就必须停止采摘。返回收集水果的最大数目。
题目挺好理解的,可以转换为最大连续子数组,并且这个连续子数组中只能有两个值。
我们还是先看暴力解法,这题的暴力解法还是挺简单的,两层循环,假设第一层为 left,第二层为 right。right 往前走,当遇到第三个数的时候就返回当前的长度。然后 left++,right = left,重复操作。
暴力之后我们在其中找到能够优化的地方,每次找到第三个数之后真的需要让 right = left 从头再走一遍吗?我们就拿题目中给的例四分析一下,如下图
当 left = 0,right = 4 的时候,此时的子数组为[3,3,3,1,2],遇到了第三个数 2,所以如果是暴力解法的话,我们记录一下此时的最长连续子数组[3,3,3,1],然后就如绿色的线条,left++ ,然后 right = left。再从头来一遍,发现还是再 right = 4 的时候遇到了第三个数,此时的最长连续子数组为[3,3,1],所以中间绿色的这几部都是没有必要的。我们直接从 left = 3 开始也就是 fruits[3] = 1;此时滑动窗口就诞生了。
那我我们应该怎么维持这个窗口呢?我们可以定义一个 hashmap,其中的 key 就是 fruits[i],value 为 fruits[i]出现的次数。
1、 进窗口
让 hashmap 存入遍历的 key,如果他不含有的话就创建一个,并且 value 赋值为 1,有的话就 value++
2、判断条件
当我们遇到第三个数的时候,我们需要将之前第一个遇到的数全部抛弃掉,所以判断条件是 hashmap.size() > 2,
3、出窗口
如果满足上述判断条件,我们就执行出窗口操作,将首次出现在窗口的数全部移除也就是上述例三直接从 left = 0 到 left = 3 这部。判断它是否全部移除就看他的 value 是否为 0,当 value 为 0 的时候,我们就直接把这个 key 从 hashmap 中移除。
4、 更新结果
在开始的时候我们定义一个 sum 用来记录最长连续子数组的长度。在这部进行判断就是
sum = Math.max(sum, right - left + 1)
代码
class Solution {
public int totalFruit(int[] f) {
HashMap<Integer,Integer> map = new HashMap<>();
int sum = 0;
for (int l = 0, r = 0; r < f.length; r++) {
//进窗口
map.put(f[r], map.getOrDefault(f[r],0) + 1);
//判断条件
while (map.size() > 2) {
int key = f[l];
//出窗口
map.put(key,map.get(key) - 1);
if (map.get(key) == 0) map.remove(key);
l++;
}
//更新结果
sum = Math.max(sum, r - l + 1);
}
return sum;
}
}