904.Fruit Into Baskets
===
###### tags: `Medium`,`Array`,`Hash Table`,`Sliding Window`
[904. Fruit Into Baskets](https://leetcode.com/problems/fruit-into-baskets/)
### 題目描述
You are visiting a farm that has a single row of fruit trees arranged from left to right. The trees are represented by an integer array `fruits` where `fruits[i]` is the **type** of fruit the i^th^ tree produces.
You want to collect as much fruit as possible. However, the owner has some strict rules that you must follow:
* You only have **two** baskets, and each basket can only hold a **single type** of fruit. There is no limit on the amount of fruit each basket can hold.
* Starting from any tree of your choice, you must pick **exactly one fruit** from **every** tree (including the start tree) while moving to the right. The picked fruits must fit in one of your baskets.
* Once you reach a tree with fruit that cannot fit in your baskets, you must stop.
Given the integer array `fruits`, return *the **maximum** number of fruits you can pick.*
### 範例
**Example 1:**
```
Input: fruits = [1,2,1]
Output: 3
Explanation: We can pick from all 3 trees.
```
**Example 2:**
```
Input: fruits = [0,1,2,2]
Output: 3
Explanation: We can pick from trees [1,2,2].
If we had started at the first tree, we would only pick from trees [0,1].
```
**Example 3:**
```
Input: fruits = [1,2,3,2,2]
Output: 4
Explanation: We can pick from trees [2,3,2,2].
If we had started at the first tree, we would only pick from trees [1,2].
```
**Constraints**:
* 1 <= `fruits.length` <= 10^5^
* 0 <= `fruits[i]` < `fruits.length`
### 解答
#### C++
```cpp=
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int ans = 0, i = 0;
unordered_map<int, int> counter;
for (int j = 0; j < fruits.size(); j++) {
counter[fruits[j]] += 1;
while (counter.size() > 2) {
counter[fruits[i]] -= 1;
if (counter[fruits[i]] == 0) counter.erase(fruits[i]);
i++;
}
ans = max(ans, j - i + 1);
}
return ans;
}
};
```
> [name=Yen-Chi Chen][time=Tue, Feb 7, 2023]
##### 思路2:
1. 找subarray, 此subarray只有兩種數字且長度是所有可能中最長的
2. 遍歷array, 遇到一個數字時, 若目前出現種類小於兩個, 或等於兩個且有出現在這兩個之中, 則當前subarray長度+1即可
3. 遇到第三種數字時, 新的subarray起點會是前一個數字往前推直到數字有變的地方為起點, 因此數字有變時要記錄index預備新array的起點, 重新計算長度
```cpp=
class Solution {
public:
int totalFruit(vector<int>& fruits) {
unordered_set<int> s;
int prev_start_index = 0, res = 1, cur_length = 1;
s.insert(fruits[0]);
for(int i = 1; i < fruits.size(); i++)
{
if(fruits[i] == fruits[i-1])
cur_length++;
else
{
if(s.size() < 2)
s.insert(fruits[i]);
else
{
if(!s.count(fruits[i]))
{
cur_length = i - prev_start_index;
int too_far_n = -1;
for(auto n : s)
{
if(n != fruits[i-1])
too_far_n = n;
}
s.erase(too_far_n);
s.insert(fruits[i]);
}
}
cur_length++;
prev_start_index = i;
}
res = max(res, cur_length);
}
return res;
}
};
```
Time: $O(n)$
Extra Space: $O(1)$
> [name=XD] [time= Feb 7, 2023]
#### Python
```python=
class Solution:
def totalFruit(self, fruits: List[int]) -> int:
ans, l = 0, 0
cnt = Counter()
for r, fruit in enumerate(fruits):
cnt[fruit] += 1
while len(cnt) > 2:
cnt[fruits[l]] -= 1
if cnt[fruits[l]] == 0:
del cnt[fruits[l]]
l += 1
ans = max(ans, r - l + 1)
return ans
```
> [name=Yen-Chi Chen][time=Tue, Feb 7, 2023]
#### Javascript
```javascript=
function totalFruit(fruits) {
let left = 0;
let max = 0;
let count = 0;
const baskets = [];
for (let i = 0; i < fruits.length; i++) {
if (baskets.includes(fruits[i])) {
count++;
} else {
if (baskets.length < 2) {
baskets.push(fruits[i]);
count++;
} else {
// 往前找到第一個不同的水果
for (let j = i - 1; j >= left; j--) {
if (fruits[j] !== fruits[i - 1]) {
left = j + 1; // 更新起始點
break;
}
}
// 重新裝水果
baskets[0] = fruits[i - 1];
baskets[1] = fruits[i];
count = i - left + 1;
}
}
max = Math.max(max, count);
}
return max;
}
```
> 參考前面兩位大神的解法寫出來了,感恩兩位大神!
> [name=Marsgoat][time=Feb 9, 2023]
### Reference
[回到題目列表](https://hackmd.io/@Marsgoat/leetcode_every_day)