问题描述
小U正在探访一座农场,农场的果树排成一列,用整数数组 fruits 表示,每个元素 fruits[i] 是第 i 棵树上的水果种类。
小U有两个篮子,每个篮子只能装一种类型的水果,而且每个篮子可以装无限量的水果。小U从任意一棵树开始,必须从每棵树上恰好采摘一个水果,并且只能装入符合篮子中水果类型的果实。如果某棵树上的水果类型不符合篮子中的水果类型,则必须停止采摘。
请你帮助小U计算他最多可以采摘多少个水果。
例如:当 fruits = [1,2,3,2,2] 时,小U最多可以采摘的树是从第2棵开始,采摘到最后的 4 棵树,结果为 [2,3,2,2]。
测试样例
样例1:
输入:
fruits = [1,2,1,2]
输出:4
样例2:
输入:
fruits = [2,0,1,2,2]
输出:3
样例3:
输入:
fruits = [1,2,3,2,2,4]
输出:4
问题分析
首先我们确定,它让我们返回的并不是出现次数最多的两个种类的和,而是在数组的某一段中,若该段仅最多有两个种类,则取这种数组长度的最大值。
对于这种求数组某一段的问题,我们可以使用滑动窗口的方法来解决。
具体地说,我们可以遍历这个数组中的每个右端点,然后判断以该点为右端点的子数组的最大长度,那么我们在遍历到该点的时候会出现两种情况,一个情况是当前采摘水果的种类还小于等于2,这个时候我们不仅可以更新答案的最大值,还可以直接开始遍历下一个点。第二个情况是当前采摘水果的种类已经大于二了,那么这个时候我们就需要移动这个子数组的左端点,直到这个子数组中仅有两个种类的水果。
对于当前子数组中存在的水果种类以及数量,可以用我之前文章中提到的Counter来实现计数。
代码实现
- 时间复杂度:O(n)
- 空间复杂度:O(1)
本题总结
数据结构选择
- Counter: 用于记录当前窗口内每种水果的数量。
- 双指针: 用于维护一个滑动窗口,确保窗口内的水果种类不超过两种。
算法步骤
-
初始化:
- 使用
Counter记录当前窗口内每种水果的数量。 - 初始化
left指针为窗口的左边界,ans记录最大采摘数量。
- 使用
-
遍历数组:
- 使用
right指针遍历数组,每次将当前水果加入Counter。 - 如果
Counter中的水果种类超过两种,则移动left指针,直到窗口内的水果种类不超过两种。
- 使用
-
更新最大值:
- 每次移动
right指针后,更新ans为当前窗口长度(right - left + 1)的最大值。
- 每次移动
-
返回结果:
- 遍历结束后,返回
ans,即小U最多可以采摘的水果数量。
- 遍历结束后,返回
双指针浅析
双指针是一种常用的算法技巧,通常用于解决数组或链表相关的问题。双指针通过在数据结构中使用两个指针,分别从不同的位置开始移动,以达到某种目标或满足某种条件。
双指针的优点
- 时间复杂度低: 通常为 O(n),因为两个指针各自遍历一次数组或链表。
- 空间复杂度低: 通常为 O(1),因为只需要常数级别的额外空间。
因此,双指针技巧在解决数组和链表问题时非常有效,能够显著提高算法的效率。