水果成篮问题

时间:2022-10-17 11:06:20

水果成篮问题

题目

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 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] 这五棵树。

题解

思路:用滑动窗口遍历fruits,当有新种类的水果进入窗口时

如果窗口中只有一种水果,将这种水果加入arr数组

如果有两种水果,更新窗口的左边界,更新arr中水果的种类

如果进来了一种新的类型的水果 更新前一种水果的位置

更新滑动窗口的最大值

复杂度:时间复杂度O(n)

空间复杂度O(1)。

JS 实现:

//[1,1,2,2]
//[1,1,2,2,3] -> [2,2,3]
var totalFruit = function(fruits) {
let l = 0;//起始指针
let maxLen = 0;//窗口的最大长度 其中最多包涵两种水果
let n = 0//前一类水果的结束位置
let arr = [fruits[l]]//水果的种类数组

for(let r = 0; r < fruits.length; r++){//窗口的右指针不断前进
if(!arr.includes(fruits[r])){//如果窗口中不包含 进窗口的水果
if(arr.length <= 1){//如果只有一种水果
arr[1] = fruits[r]//将这种水果加入arr数组
}else{//如果有两种水果
l = n//更新窗口的左边界
arr[0] = fruits[r-1]//更新arr中水果的种类
arr[1] = fruits[r]
}
}

if(fruits[r] !== fruits[n]){//如果进来了一种新的类型的水果 更新前一种水果的位置
n = r
}

maxLen = Math.max(maxLen,r-l+1)//更新滑动窗口的最大值
}
return maxLen

};

总结

也可以利用 map 的有序特点:

function totalFruit(fruits: number[]): number {
// 左指针
let p = 0
// 函数返回的最大值
let max = 0
// Map 记录水果类型(key)和最新对应的索引值(value)
const fruitsMap: Map<number, number> = new Map()
for (let i = 0; i < fruits.length; i++) {
const fruit = fruits[i]
if (fruitsMap.has(fruit)) {
// 利用 Map 的有序性,将 Map 中已有的水果删除后再重新添加,保证最新访问的水果在 Map 的最后面
fruitsMap.delete(fruit)
} else {
if (fruitsMap.size === 2) {
// 如果访问到第三种水果类型,此时需要删除最久未访问过的水果
// 取 Map 中第一个水果的信息(就是最久未访问过的水果)
const iterator = fruitsMap.entries()
const [firstFruit, firstFruitIndex] = iterator.next().value
// 此时左指针应该指向 Map 中 第一个水果类型的索引加 1(也就是第二个水果类型的起始位置)
p = firstFruitIndex + 1
// 删除 Map 中第一个水果
fruitsMap.delete(firstFruit)
}
}
fruitsMap.set(fruit, i)
max = Math.max(i - p + 1, max)
}
return max
}