[LeetCode] 904. Fruit Into Baskets 水果装入果篮
In a row of trees, the `i`-th tree produces fruit with type `tree[i]`.
You start at any tree of your choice, then repeatedly perform the following steps:
- Add one piece of fruit from this tree to your baskets. If you cannot, stop.
- Move to the next tree to the right of the current tree. If there is no tree to the right, stop.
Note that you do not have any choice after the initial choice of starting tree: you must perform step 1, then step 2, then back to step 1, then step 2, and so on until you stop.
You have two baskets, and each basket can carry any quantity of fruit, but you want each basket to only carry one type of fruit each.
What is the total amount of fruit you can collect with this procedure?
Example 1:
Input: [1,2,1]
Output: 3
Explanation: We can collect [1,2,1].
Example 2:
Input: [0,1,2,2]
Output: 3 Explanation: We can collect [1,2,2].
If we started at the first tree, we would only collect [0, 1].
Example 3:
Input: [1,2,3,2,2]
Output: 4 Explanation: We can collect [2,3,2,2].
If we started at the first tree, we would only collect [1, 2].
Example 4:
Input: [3,3,3,1,2,1,1,2,3,3,4]
Output: 5 Explanation: We can collect [1,2,1,1,2].
If we started at the first tree or the eighth tree, we would only collect 4 fruits.
Note:
1 <= tree.length <= 400000 <= tree[i] < tree.length
这道题说是给了我们一排树,每棵树产的水果种类是 tree[i],说是现在有两种操作,第一种是将当前树的水果加入果篮中,若不能加则停止;第二种是移动到下一个树,若没有下一棵树,则停止。现在我们有两个果篮,可以从任意一个树的位置开始,但是必须按顺序执行操作一和二,问我们最多能收集多少个水果。说实话这道题的题目描述确实不太清晰,博主看了很多遍才明白意思,论坛上也有很多吐槽的帖子,但实际上这道题的本质就是从任意位置开始,若最多只能收集两种水果,问最多能收集多少个水果。那么再进一步提取,其实就是最多有两个不同字符的最长子串的长度,跟之前那道 [Longest Substring with At Most Two Distinct Characters](http://www.cnblogs.com/grandyang/p/5185561.html) 一模一样,只不过换了一个背景,代码基本都可以直接使用的,博主感觉这样出题有点不太好吧,完全重复了。之前那题的四种解法这里完全都可以使用,先来看第一种,使用一个 HashMap 来记录每个水果出现次数,当 HashMap 中当映射数量超过两个的时候,我们需要删掉一个映射,做法是滑动窗口的左边界 start 的水果映射值减1,若此时减到0了,则删除这个映射,否则左边界右移一位。当映射数量回到两个的时候,用当前窗口的大小来更新结果 res 即可,参见代码如下:
解法一:
class Solution {
public:
int totalFruit(vector<int>& tree) {
int res = 0, start = 0, n = tree.size();
unordered_map<int, int> fruitCnt;
for (int i = 0; i < n; ++i) {
++fruitCnt[tree[i]];
while (fruitCnt.size() > 2) {
if (--fruitCnt[tree[start]] == 0) {
fruitCnt.erase(tree[start]);
}
++start;
}
res = max(res, i - start + 1);
}
return res;
}
};
我们除了用 HashMap 来映射字符出现的个数,我们还可以映射每个数字最新的坐标,比如题目中的例子 [0,1,2,2],遇到第一个0,映射其坐标0,遇到1,映射其坐标1,当遇到2时,映射其坐标2,每次我们都判断当前 HashMap 中的映射数,如果大于2的时候,那么需要删掉一个映射,我们还是从 start=0 时开始向右找,看每个字符在 HashMap 中的映射值是否等于当前坐标 start,比如0,HashMap 此时映射值为0,等于 left 的0,那么我们把0删掉,start 自增1,再更新结果,以此类推直至遍历完整个数组,参见代码如下:
解法二:
class Solution {
public:
int totalFruit(vector<int>& tree) {
int res = 0, start = 0, n = tree.size();
unordered_map<int, int> fruitPos;
for (int i = 0; i < n; ++i) {
fruitPos[tree[i]] = i;
while (fruitPos.size() > 2) {
if (fruitPos[tree[start]] == start) {
fruitPos.erase(tree[start]);
}
++start;
}
res = max(res, i - start + 1);
}
return res;
}
};
后来又在网上看到了一种解法,这种解法是维护一个滑动窗口 sliding window,指针 left 指向起始位置,right 指向 window 的最后一个位置,用于定位 left 的下一个跳转位置,思路如下:
若当前字符和前一个字符相同,继续循环。
若不同,看当前字符和 right 指的字符是否相同:
若相同,left 不变,右边跳到 i - 1。
若不同,更新结果,left 变为 right+1,right 变为 i - 1。
最后需要注意在循环结束后,我们还要比较结果 res 和 n - left 的大小,返回大的,这是由于如果数组是 [5,3,5,2,1,1,1],那么当 left=3 时,i=5,6 的时候,都是继续循环,当i加到7时,跳出了循环,而此时正确答案应为 [2,1,1,1] 这4个数字,而我们的结果 res 只更新到了 [5,3,5] 这3个数字,所以我们最后要判断 n - left 和结果 res 的大小。
另外需要说明的是这种解法仅适用于于不同字符数为2个的情况,如果为k个的话,还是需要用上面两种解法。
解法三:
class Solution {
public:
int totalFruit(vector<int>& tree) {
int res = 0, left = 0, right = -1, n = tree.size();
for (int i = 1; i < n; ++i) {
if (tree[i] == tree[i - 1]) continue;
if (right >= 0 && tree[right] != tree[i]) {
res = max(res, i - left);
left = right + 1;
}
right = i - 1;
}
return max(n - left, res);
}
};
还有一种不使用 HashMap 的解法,这里我们使用若干个变量,其中 cur 为当前最长子数组的长度,a和b为当前候选的两个不同的水果种类,cntB 为水果b的连续个数。我们遍历所有数字,假如遇到的水果种类是a和b中的任意一个,那么 cur 可以自增1,否则 cntB 自增1,因为若是新水果种类的话,默认已经将a种类淘汰了,此时候选水果由类型b和这个新类型水果构成,所以当前长度是 cntB+1。然后再来更新 cntB,假如当前水果种类是b的话,cntB 自增1,否则重置为1,因为 cntB 统计的就是水果种类b的连续个数。然后再来判断,若当前种类不是b,则此时a赋值为b, b赋值为新种类。最后不要忘了用 cur 来更新结果 res,参见代码如下:
解法四:
class Solution {
public:
int totalFruit(vector<int>& tree) {
int res = 0, cur = 0, cntB = 0, a = 0, b = 0;
for (int fruit : tree) {
cur = (fruit == a || fruit == b) ? cur + 1 : cntB + 1;
cntB = (fruit == b) ? cntB + 1 : 1;
if (b != fruit) {
a = b; b = fruit;
}
res = max(res, cur);
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/904
参考资料:
https://leetcode.com/problems/fruit-into-baskets/
https://leetcode.com/problems/fruit-into-baskets/discuss/170740/Sliding-Window-for-K-Elements
[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)
[LeetCode] 904. Fruit Into Baskets 水果装入果篮的更多相关文章
- Leetcode 904. Fruit Into Baskets
sliding window(滑动窗口)算法 class Solution(object): def totalFruit(self, tree): """ :type ...
- 【LeetCode】904. Fruit Into Baskets 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/fruit-in ...
- [Swift]LeetCode904. 水果成篮 | Fruit Into Baskets
In a row of trees, the i-th tree produces fruit with type tree[i]. You start at any tree of your cho ...
- LeetCode - Fruit Into Baskets
In a row of trees, the i-th tree produces fruit with type tree[i]. You start at any tree of your cho ...
- All LeetCode Questions List 题目汇总
All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- [LeetCode] Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串
Given a string S, find the length of the longest substring T that contains at most two distinct char ...
- LeetCode Longest Substring with At Most Two Distinct Characters
原题链接在这里:https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/ 题目: Gi ...
- [LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串
Given a string s , find the length of the longest substring t that contains at most 2 distinct char ...
随机推荐
- 移动端js触摸touch详解(附带案例源码)
移动端触摸滑动原理详解案例,实现过程通过添加DOM标签的触摸事件监听,并计算触摸距离,通过距离坐标计算触摸角度,最后通过触摸角度去判断往哪个方向触摸的. 触摸的事件列表 触摸的4个事件: touchs ...
- POJ-2006 Litmus Test 高精度
The pH scale measures the concentration of protons (H +) in a solution and, therefore, its acidity o ...
- Topshelf + QuartzNet 实现挂载在 WIndows Services 中的定时任务
直接贴代码了: 首先我们可以把所有的 Job 放到一个单独的 DLL 中,好处是可以共享这些业务 Job.比如我们新建一个 QuartzNetDemo.WinService.Jobs 的类库. 然后, ...
- 一个简单的利用 WebClient 异步下载的示例(五)(完结篇)
接着上一篇,我们继续来优化.我们的 SkyParallelWebClient 可否支持切换“同步下载模式”和“异步下载模式”呢,好处是大量的代码不用改,只需要调用 skyParallelWebClie ...
- JavaScript定时器越走越快的问题
目录 JavaScript定时器越走越快的问题 (setinterval)多次初始化 清除(clearInterval)的失效 解决方法 JavaScript定时器越走越快的问题 之前在项目中写了定时 ...
- Child module D:\program\eclipse\eclipse\workspace_taotao\taotao-parent\taotao-manager-service of
1.淘淘商城的项目,报了这个错误,也是一脸懵逼. [INFO] Scanning for projects... [ERROR] [ERROR] Some problems were encounte ...
- 博文与文档发布玩法:Github + MWeb + 语雀 + Cnbolgs
本文会说两个话题, 1,如何将 Github 上的文档(如:dotnet-campus/doraemon-pocket: 哆啦A梦的口袋 - 收集效率工具与站点)发布到语雀. 2,如何在本地使用 Ma ...
- 面试题深入解析:Synchronized底层实现
本文为synchronized系列第二篇.主要内容为分析偏向锁的实现. 偏向锁的诞生背景和基本原理在上文中已经讲过了,强烈建议在有看过上篇文章的基础下阅读本文. 本文将分为几块内容: 1.偏向锁的入口 ...
- mask-rcnn代码解读(五):mask_iou的计算
我以为只有box能计算iou值,但我看了maskrcnn后,发现该模型对mask进行了iou的计算,该方法巧妙之处在于 mask1与mask2必须有相同的height and width,而后在同一个 ...
- 面试阿里百分百问的Jvm,别问有没有必要学,真的很有必要朋友
面试阿里百分百问的Jvm,别问有没有必要学,真的很有必要朋友 前言: JVM 的内存模型和 JVM 的垃圾回收机制一直是 Java 业内从业者绕不开的话题(实际调优.面试)JVM是java中很重要的一 ...