904.水果成篮

297 阅读2分钟

904.水果成篮

LeetCode

描述:

在一排树中,第 i 棵树产生 tree[i] 型的水果。 你可以从你选择的任何树开始,然后重复执行以下步骤:

  1. 把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
  2. 移动到当前树右侧的下一棵树。如果右边没有树,就停下来。

请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。

你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。

用这个程序你能收集的水果树的最大总量是多少?

示例 1:

输入:[1,2,1] 输出:3 解释:我们可以收集 [1,2,1]。 示例 2:

输入:[0,1,2,2] 输出:3 解释:我们可以收集 [1,2,2] 如果我们从第一棵树开始,我们将只能收集到 [0, 1]。

  • 这个题目描述的比较迷, 主要看题目讲述的两个步骤, 和示例, 可以分析出题目要求, 也即在一个数组中, 找出一个子数组, 这个子数组只能含有两个元素, 需要返回找到的最长的子数组的长度.

思路:

  • 求子数组, 一般可以处理为滑动窗口法, 即双指针法, 这里我看到了LeetCode的一个题解所说的滑动窗口题目的一个模板, 比较有意义, 在这里引用一下: 求最长子数组长度,直滑动窗口模板。

    最长窗口模板(引用链接)

    for(枚举选择)
        右边界
        while(不符合条件)
            左边界
        更新结果
    

代码:

/*
 * @lc app=leetcode.cn id=904 lang=cpp
 *
 * [904] 水果成篮
 */

// @lc code=start
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
      unordered_map<int, int> window;
        int res = 0;
        for (int left = 0, right = 0; right < fruits.size(); right++) {
            window[fruits[right]]++;
            while (window.size() > 2) {
                window[fruits[left]]--;
                if (window[fruits[left]] == 0) {
                    window.erase(fruits[left]);
                }
                left++;
            }
            res = max(res, right - left + 1);
        }

        return res;

    }
};
  • 时间复杂度:O(N),其中 N 是 tree 的长度。
  • 空间复杂度:O(N)。
  • 这里使用到了C++的STL标准库中的“无序map容器”, 上述代码中14行: window[fruits[right]]++; 可直接将window赋值, 其中, fruits[right]为key, “++”操作后, key对应的值为加一, 初始值为0.

参考:

  1. 【中规中矩】904. 水果成篮 (披上马甲的滑窗问题)

  2. 套模板!滑动窗口求最长子数组!

  3. 904.水果成篮(官方题解)