2Brute2Best
🔥0

Fruit Into Baskets

Medium·LeetCode #904Basic Anchor
LeetCode
30-Second Mental ModelVariable Sliding Window + Frequency Map
Complexity:O(N²)→O(N)
Key Insight

Keep one window [left … right] and a map count[type] of how many fruits of each type are inside. The number of keys in the map is the number of types. Grow the window on the right every step. If a third type appears, move left forward and drop fruits until one type's count reaches 0 and it is removed from the map. Then the window is valid again, and its length is a candidate answer.

Core Validity Invariant

The window is valid when it contains at most 2 distinct fruit types (count.size() ≤ 2). How many fruits of each type does not matter.

01

Problem

There is a row of fruit trees. fruits[i] is the type of fruit on tree i.

You have two baskets, and each basket can hold only one type of fruit (but as many fruits of that type as you like).

You pick a starting tree and walk right, picking exactly one fruit from every tree you pass. You must stop as soon as you reach a tree whose fruit fits in neither basket.

Return the most fruits you can pick.

In other words: find the longest contiguous subarray that contains at most 2 different values.

Input

An integer array fruits, where fruits[i] is the type of fruit on tree i.

Output

One integer: the length of the longest contiguous subarray with at most 2 distinct values.

Example 1
Input: fruits = [1, 2, 1]
Output: 3

Only 2 types (1 and 2), so you can pick from all three trees.

Example 2
Input: fruits = [0, 1, 2, 2]
Output: 3

Start at tree 1 and pick [1, 2, 2]. Starting at tree 0 would stop at the third type (2) after only 2 fruits.

Example 3
Input: fruits = [1, 2, 3, 2, 2]
Output: 4

Pick [2, 3, 2, 2] starting from tree 1.

Constraints
  • • 1 ≤ fruits.length ≤ 10^5
  • • 0 ≤ fruits[i] < fruits.length
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    Do the picked trees have to be next to each other, or can I skip trees?

  2. 2.

    What does "two baskets, one type each" really limit — the number of fruits, or the number of different types?

  3. 3.

    If a block of trees is fine, is every smaller block inside it also fine?

  4. 4.

    When a third type shows up, which trees could I stop picking from to make it fine again?

  5. 5.

    What do I need to remember about the current block to know how many types it has?

03

Brute force approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceFor each start, walk right until a third type appearsO(N²)O(1)
OptimalGrow right; while there are 3 types, shrink left until one type is goneO(N)O(1)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “walk right from a starting tree, picking from every tree”The answer is a contiguous range [l … r] → think window.
  • “maximum number of fruits”We want the longest valid range → variable window that grows on the right and shrinks on the left.
  • “two baskets, one type each”At most 2 distinct values in the window → we need the counts of each value to know when a value fully leaves.
Contiguous range+maximum length+at most 2 distinct values→Variable Sliding Window + Frequency Map

This is the anchor of the frequency-map family. The window rule depends on what is inside the window (how many distinct types), not on a sum. Learn the core moves here: add on the right, remove on the left, and delete a key when its count reaches 0 so that count.size() is the number of distinct types. The next questions keep the same loop and only change the rule: exactly k distinct (GFG K Uniques), length − maxFreq ≤ k (Character Replacement), every count ≤ k (LC 2958), or covering a target (Minimum Window).

10

Don't make this mistake

Pattern confusion: using the Character Replacement rule
✗ while ((right - left + 1) - maxFreq > 2) { ... }
✓ while (count.size() > 2) { ... }

Fruit Into Baskets is NOT windowSize − maxFrequency ≤ 2; the condition is distinct types ≤ 2. windowSize − maxFreq counts how many fruits are not the most common type — that is the rule for Longest Repeating Character Replacement. Here, [1,2,1,2,1,2] is perfectly valid (2 types) even though 6 − 3 = 3 > 2.

Forgetting to erase a type when its count hits 0
✗ count[fruits[left]]--; left++;
✓ count[fruits[left]]--; if (count[fruits[left]] == 0) count.erase(fruits[left]); left++;

count.size() counts keys, including keys with value 0. If you don't erase, a type that already left the window still counts as a basket, and the loop shrinks forever (or far too much).

Using `if` instead of `while` to shrink
✗ if (count.size() > 2) { /* remove one fruit */ }
✓ while (count.size() > 2) { /* remove one fruit */ }

Removing one fruit may not remove a whole type. In [3,3,3,1,2], when 2 arrives you must drop all three 3s before the window is valid again.

Shrinking to just the last fruit

Some people reset left = right when a third type appears. That throws away the fruits of the type just before right, which can still be picked. For [1,2,1,1,3,1,1] the answer is 5 ([1,1,3,1,1]), but resetting to [3] gives only 4. Shrink one step at a time until a type disappears.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Sliding Window translate into production architectures and low-level memory mechanics.