一:题目描述:
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits
表示,其中 fruits[i]
是第 i
棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
- 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits
,返回你可以收集的水果的 最大 数目。
二:示例与提示
示例 1:
1 | 输入:fruits = [1,2,1] |
示例 2:
1 | 输入:fruits = [0,1,2,2] |
示例 3:
1 | 输入:fruits = [1,2,3,2,2] |
示例 4:
1 | 输入:fruits = [3,3,3,1,2,1,1,2,3,3,4] |
提示:
1 <= fruits.length <= 105
0 <= fruits[i] < fruits.length
三:思路
暴力求解法
两层循环遍历,找到所有情况
- 外层循环控制起始位置
- 内层循环控制终止位置
- 两层嵌套,找到满足小于等于两种水果的所有情况,然后返回最大长度
该结果会超时
滑动窗口
- 当出现第三种水果时候,窗口应该缩小,直到满足还是小于等于两种水果的情况
- 当满足小于等于两种情况时候,窗口自动扩大,右指针向右移动
- 使用map数据结构来对水果进行存储
set数据结构不行
- set数据结构是无法实现的
- 因为set集合只会存在不同的元素,相同的元素无法存储,也无法存储每个元素出现的次数
- 无法记录该元素的次数,就无法正确地移动左指针,就无法正确的记录每个正常情况下的长度值
输入
1 | [3,3,3,1,2,1,1,2,3,3,4] |
- 使用set数据结构存储水果数量时候,可以看到右指针是正确移动的,但是左指针只移动了一次
- 虽然前三个案例是可以通过
- 但出现多个重复水果时候,就会由于集合中无法记录不同水果出现的次数,导致无法正确移动左指针
- 导致长度计算出现问题
- 正确应该当出现3,1,2情况时,left指针已经移动到了最后一个3,但他还是在第一个3,所以只能使用map数据结构来存储元素次数
四:代码 + 复杂度分析
暴力求解
1 | /** |
时间复杂度:O(n ^ 2)
空间复杂度:O(1)
滑动窗口
1 | /** |
- 时间复杂度:O(n)
- 外层循环从
right = 0
遍历到right = n - 1
,其中n
是输入数组fruits
的长度。这一步的时间复杂度是 O(n) - 内层循环是一个
while
循环,它会在窗口中水果种类数大于2时缩小窗口。在最坏情况下,内层循环会将窗口从右到左移动,因此最多会遍历一次整个数组。因此,内层循环的时间复杂度也是 O(n) - 整体算法复杂度不是O(n ^ 2),因为这是因为这两个循环并不会同时遍历整个数组的所有元素,内层循环当满足条件小于等于2时候,内层while循环就不执行,一旦窗口中的水果种类数恢复到2以下,就会退出内层循环,内层
while
循环的最坏的时间复杂度也是 O(n),但它并不会导致整体的算法复杂度为 O(n^2)
- 外层循环从
- 空间复杂度:O(1)