Skip to content

feat: add solutions to lc problem: No.0904 #4620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions solution/0900-0999/0904.Fruit Into Baskets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ tags:

### 方法一:哈希表 + 滑动窗口

我们用哈希表 $cnt$ 维护当前窗口内的水果种类以及对应的数量,用双指针 $j$ 和 $i$ 维护窗口的左右边界。
我们用哈希表 $\textit{cnt}$ 维护当前窗口内的水果种类以及对应的数量,用双指针 $j$ 和 $i$ 维护窗口的左右边界。

遍历数组 `fruits`,将当前水果 $x$ 加入窗口,即 $cnt[x]++$,然后判断当前窗口内的水果种类是否超过了 $2$ 种,如果超过了 $2$ 种,就需要将窗口的左边界 $j$ 右移,直到窗口内的水果种类不超过 $2$ 种为止。然后更新答案,即 $ans = \max(ans, i - j + 1)$。
遍历数组 $\textit{fruits}$,将当前水果 $x$ 加入窗口,即 $\textit{cnt}[x]++$,然后判断当前窗口内的水果种类是否超过了 $2$ 种,如果超过了 $2$ 种,就需要将窗口的左边界 $j$ 右移,直到窗口内的水果种类不超过 $2$ 种为止。然后更新答案,即 $\textit{ans} = \max(\textit{ans}, i - j + 1)$。

遍历结束后,即可得到最终的答案。

Expand All @@ -105,7 +105,7 @@ j i
j i
```

时间复杂度 $O(n)$,其中 $n$ 为数组 `fruits` 的长度。空间复杂度 $O(1)$。
时间复杂度 $O(n)$,其中 $n$ 为数组 $\textit{fruits}$ 的长度。空间复杂度 $O(1)$,因为哈希表 $\textit{cnt}$ 中的键值对数量最多为 $2$。

<!-- tabs:start -->

Expand Down Expand Up @@ -248,19 +248,49 @@ impl Solution {
}
```

#### C#

```cs
public class Solution {
public int TotalFruit(int[] fruits) {
var cnt = new Dictionary<int, int>();
int ans = 0;
for (int i = 0, j = 0; i < fruits.Length; ++i) {
int x = fruits[i];
if (cnt.ContainsKey(x)) {
cnt[x]++;
} else {
cnt[x] = 1;
}
while (cnt.Count > 2) {
int y = fruits[j++];
if (cnt.ContainsKey(y)) {
cnt[y]--;
if (cnt[y] == 0) {
cnt.Remove(y);
}
}
}
ans = Math.Max(ans, i - j + 1);
}
return ans;
}
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- solution:start -->

### 方法二:滑动窗口优化
### 方法二:单调变长滑动窗口

在方法一中,我们发现,窗口大小会时而变大,时而变小,这就需要我们每一次更新答案。

但本题实际上求的是水果的最大数目,也就是“最大”的窗口,我们没有必要缩小窗口,只需要让窗口单调增大。于是代码就少了每次更新答案的操作,只需要在遍历结束后将此时的窗口大小作为答案返回即可。

时间复杂度 $O(n)$,其中 $n$ 为数组 `fruits` 的长度。空间复杂度 $O(1)$
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\textit{fruits}$ 的长度。

<!-- tabs:start -->

Expand Down Expand Up @@ -395,6 +425,35 @@ impl Solution {
}
```

#### C#

```cs
public class Solution {
public int TotalFruit(int[] fruits) {
var cnt = new Dictionary<int, int>();
int j = 0, n = fruits.Length;
foreach (int x in fruits) {
if (cnt.ContainsKey(x)) {
cnt[x]++;
} else {
cnt[x] = 1;
}

if (cnt.Count > 2) {
int y = fruits[j++];
if (cnt.ContainsKey(y)) {
cnt[y]--;
if (cnt[y] == 0) {
cnt.Remove(y);
}
}
}
}
return n - j;
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
67 changes: 63 additions & 4 deletions solution/0900-0999/0904.Fruit Into Baskets/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ If we had started at the first tree, we would only pick from trees [1,2].

We use a hash table $cnt$ to maintain the types and corresponding quantities of fruits in the current window, and use two pointers $j$ and $i$ to maintain the left and right boundaries of the window.

We traverse the `fruits` array, add the current fruit $x$ to the window, i.e., $cnt[x]++$, then judge whether the types of fruits in the current window exceed $2$. If it exceeds $2$, we need to move the left boundary $j$ of the window to the right until the types of fruits in the window do not exceed $2$. Then we update the answer, i.e., $ans = \max(ans, i - j + 1)$.
We traverse the $\textit{fruits}$ array, add the current fruit $x$ to the window, i.e., $cnt[x]++$, then judge whether the types of fruits in the current window exceed $2$. If it exceeds $2$, we need to move the left boundary $j$ of the window to the right until the types of fruits in the window do not exceed $2$. Then we update the answer, i.e., $ans = \max(ans, i - j + 1)$.

After the traversal ends, we can get the final answer.

Expand All @@ -95,7 +95,7 @@ j i
j i
```

The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the `fruits` array.
The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the $\textit{fruits}$ array.

<!-- tabs:start -->

Expand Down Expand Up @@ -238,19 +238,49 @@ impl Solution {
}
```

#### C#

```cs
public class Solution {
public int TotalFruit(int[] fruits) {
var cnt = new Dictionary<int, int>();
int ans = 0;
for (int i = 0, j = 0; i < fruits.Length; ++i) {
int x = fruits[i];
if (cnt.ContainsKey(x)) {
cnt[x]++;
} else {
cnt[x] = 1;
}
while (cnt.Count > 2) {
int y = fruits[j++];
if (cnt.ContainsKey(y)) {
cnt[y]--;
if (cnt[y] == 0) {
cnt.Remove(y);
}
}
}
ans = Math.Max(ans, i - j + 1);
}
return ans;
}
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- solution:start -->

### Solution 2: Sliding Window Optimization
### Solution 2: Monotonic Variable-Length Sliding Window

In Solution 1, we find that the window size sometimes increases and sometimes decreases, which requires us to update the answer each time.

But what this problem actually asks for is the maximum number of fruits, that is, the "largest" window. We don't need to shrink the window, we just need to let the window monotonically increase. So the code omits the operation of updating the answer each time, and only needs to return the size of the window as the answer after the traversal ends.

The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the `fruits` array.
The time complexity is $O(n)$, and the space complexity is $O(n)$, where $n$ is the length of the $\textit{fruits}$ array.

<!-- tabs:start -->

Expand Down Expand Up @@ -385,6 +415,35 @@ impl Solution {
}
```

#### C#

```cs
public class Solution {
public int TotalFruit(int[] fruits) {
var cnt = new Dictionary<int, int>();
int j = 0, n = fruits.Length;
foreach (int x in fruits) {
if (cnt.ContainsKey(x)) {
cnt[x]++;
} else {
cnt[x] = 1;
}

if (cnt.Count > 2) {
int y = fruits[j++];
if (cnt.ContainsKey(y)) {
cnt[y]--;
if (cnt[y] == 0) {
cnt.Remove(y);
}
}
}
}
return n - j;
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
25 changes: 25 additions & 0 deletions solution/0900-0999/0904.Fruit Into Baskets/Solution.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
public class Solution {
public int TotalFruit(int[] fruits) {
var cnt = new Dictionary<int, int>();
int ans = 0;
for (int i = 0, j = 0; i < fruits.Length; ++i) {
int x = fruits[i];
if (cnt.ContainsKey(x)) {
cnt[x]++;
} else {
cnt[x] = 1;
}
while (cnt.Count > 2) {
int y = fruits[j++];
if (cnt.ContainsKey(y)) {
cnt[y]--;
if (cnt[y] == 0) {
cnt.Remove(y);
}
}
}
ans = Math.Max(ans, i - j + 1);
}
return ans;
}
}
24 changes: 24 additions & 0 deletions solution/0900-0999/0904.Fruit Into Baskets/Solution2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
public class Solution {
public int TotalFruit(int[] fruits) {
var cnt = new Dictionary<int, int>();
int j = 0, n = fruits.Length;
foreach (int x in fruits) {
if (cnt.ContainsKey(x)) {
cnt[x]++;
} else {
cnt[x] = 1;
}

if (cnt.Count > 2) {
int y = fruits[j++];
if (cnt.ContainsKey(y)) {
cnt[y]--;
if (cnt[y] == 0) {
cnt.Remove(y);
}
}
}
}
return n - j;
}
}