Java_滑动窗口_水果成篮

50 阅读4分钟

题目链接: 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 <= 105
  • 0 <= fruits[i] < fruits.length

题目解析

给了一个整数数组 fruitsfruits[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;
    }
}