水果成篮 | LeetCode-904 | 双指针 | 哈希集合 | 哈希数组

能用哈希哈希集合解决的问题,大概率也可以使用哈希集合

LeetCode链接:904. 水果成篮

1.题目描述

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

1
2
3
输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

1
2
3
4
输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

1
2
3
4
输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

1
2
3
输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

提示:

  • $1 <= fruits.length <= 10^5$
  • 0 <= fruits[i] < fruits.length

2.题解

2.1 哈希集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public int totalFruit(int[] fruits) {
// 使用哈希表记录每种水果的数量
Map<Integer, Integer> map = new HashMap<>();
// 左指针(滑动窗口的左边界)
int left = 0;
// 用于存储当前可以收集到的最大水果数量
int max = 0;
// 右指针(滑动窗口的右边界)
for (int right = 0; right < fruits.length; right++) {
// 将当前水果加入哈希表,并增加其数量
map.put(fruits[right], map.getOrDefault(fruits[right], 0) + 1);
// 如果哈希表中的水果种类超过了两种,则移动左指针收缩窗口
while (map.size() > 2) {
// 减少左边水果的数量
map.put(fruits[left], map.get(fruits[left]) - 1);
// 如果某种水果的数量减少到0,则将其从哈希表中移除
if (map.get(fruits[left]) == 0) {
map.remove(fruits[left]);
}
// 左指针右移,缩小窗口
left++;
}
// 更新最大收集水果数量,窗口的大小为 right - left + 1
max = Math.max(max, right - left + 1);
}
// 返回最大可以收集的水果数量
return max;
}
}

2.2 哈希数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int totalFruit(int[] fruits) {
// 用于记录每种水果在当前窗口中的数量
int[] map = new int[fruits.length];
int maxFruits = 0; // 存储最大连续水果数量
int types = 0; // 记录当前窗口内的水果种类数
int left = 0; // 滑动窗口的左边界

// 遍历水果数组
for (int right = 0; right < fruits.length; right++) {
// 如果当前水果种类第一次出现,增加种类数
if (map[fruits[right]] == 0) types++;
map[fruits[right]]++;
// 如果水果种类超过2种,收缩左边界
while (types > 2) {
map[fruits[left]]--;
// 如果一种水果的数量减少到0,则减少种类数
if (map[fruits[left]] == 0) types--;
left++;
}
// 计算当前窗口的最大水果数量
maxFruits = Math.max(maxFruits, right - left + 1);
}
return maxFruits; // 返回最大连续水果数量
}
}
  • 精简版:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public int totalFruit(int[] fruits) {
// 用于记录每种水果的数量
int[] map = new int[fruits.length];

int maxFruits = 0; // 存储最大连续水果数量
int types = 0; // 记录当前的水果种类数
int left = 0; // 滑动窗口的左边界
// 遍历所有水果
for (int right = 0; right < fruits.length; right++) {
// 如果当前水果种类第一次出现,增加种类数
if (map[fruits[right]]++ == 0) types++;
// 如果水果种类超过2种,收缩左边界
while (types > 2) {
if (--map[fruits[left++]] == 0) types--;
}
// 计算当前窗口的最大水果数量
maxFruits = Math.max(maxFruits, right - left + 1);
}

return maxFruits; // 返回最大连续水果数量
}
}
-------------本文结束感谢您的阅读-------------