写点什么

水果成篮问题

作者:掘金安东尼
  • 2022-10-17
    广东
  • 本文字数:1692 字

    阅读完需:约 1 分钟

题目

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


发布于: 刚刚阅读数: 3
用户头像

安东尼陪你度过漫长编程岁月~ 2022-07-14 加入

真正的大师,永远怀着一颗学徒的心(易)

评论

发布
暂无评论
水果成篮问题_算法_掘金安东尼_InfoQ写作社区