Back to Arrays
Q109Question 109 of 109

Fruits into Baskets (Longest Subarray with At Most Two Distinct Values)

Key Concepts
  • Two baskets means at most two distinct types, so the problem reduces to the longest window with two distinct values.
  • Use a variable-size sliding window with a frequency map; shrink when distinct types exceed two.
  • Remove a type from the map when its count reaches zero to keep the distinct count accurate.
  • The solution runs in O(n) time with O(1) extra space since the map never holds more than three keys transiently.
  • The same template generalizes to any k-distinct-values problem by parameterizing the limit.
  • The main interview insight is spotting the reduction from the fruit framing to a known sliding-window pattern.

Definition

Two baskets means at most two distinct types, so it is the longest window with two distinct values.
  • Problem reduction – two baskets, each holding one fruit type, means the window can contain at most two distinct types.
  • Sliding window – expand right, adding each type's count; shrink left when distinct types exceed two.
  • Frequency map – tracks the count of each type in the current window; remove a type when its count hits zero.
  • Generalization – the same template solves "longest subarray with at most k distinct values" for any k.
  • Complexity – O(n) time, O(1) space (map holds at most 3 keys transiently).

At the National Bank of India, Rajesh walks along a row of trading desks, each running one instrument type. He carries two baskets (can track at most two instrument types). He must collect from every desk he passes until he would need a third basket. The question is the longest continuous run using at most two instrument types.

Understanding the Concepts

What is the problem?

You walk along a row of trees, each producing one type of fruit. You have two baskets, each holding only one type. You must pick from every tree you pass, moving right, until you encounter a third type. Find the maximum number of fruits you can collect.

This is exactly the longest subarray with at most two distinct values.

Why is pattern recognition the key insight?

The fruit-and-basket framing is a disguise for the k-distinct sliding window where k = 2. Candidates who try to invent a bespoke basket simulation overcomplicate it. Recognizing the reduction is the main value of this problem in an interview.

How does the sliding window solution work?

JAVA
package com.bank.analytics;

import java.util.HashMap;
import java.util.Map;

public class FruitsIntoBaskets {
    public static int totalFruit(int[] trees) {
        Map<Integer, Integer> basket = new HashMap<>();
        int left = 0;
        int maxFruits = 0;

        for (int right = 0; right < trees.length; right++) {
            basket.merge(trees[right], 1, Integer::sum);

            while (basket.size() > 2) {
                int leftType = trees[left];
                basket.merge(leftType, -1, Integer::sum);
                if (basket.get(leftType) == 0) {
                    basket.remove(leftType);
                }
                left++;
            }

            maxFruits = Math.max(maxFruits, right - left + 1);
        }
        return maxFruits;
    }

    public static void main(String[] args) {
        int[] trees = {1, 2, 1, 3, 4, 3, 5, 5, 5};
        System.out.println("Max fruits: " + totalFruit(trees));
    }
}
TEXT
Max fruits: 4

Why remove the key when count reaches zero?

The map's size represents the number of distinct types in the window. If you leave a key with count zero, the map falsely reports three distinct types even when there are only two.

JAVA
// Wrong: leaves dead keys
basket.put(leftType, basket.get(leftType) - 1);
// basket.size() is still 3 even if one type's count is 0

// Correct: remove when count reaches 0
basket.merge(leftType, -1, Integer::sum);
if (basket.get(leftType) == 0) basket.remove(leftType);

What is the step-by-step trace?

For trees [1, 2, 1, 3, 4, 3, 5, 5, 5]:

  • right=0: basket={1:1}. Window [1]. max=1.
  • right=1: basket={1:1, 2:1}. Window [1,2]. max=2.
  • right=2: basket={1:2, 2:1}. Window [1,2,1]. max=3.
  • right=3: basket={1:2, 2:1, 3:1}. Size 3, shrink: remove trees[0]=1, count 1:1. Still 3 types. Remove trees[1]=2, count 2:0, remove key. basket={1:1, 3:1}. left=2. Window [1,3]. max=3.
  • right=4: basket={1:1, 3:1, 4:1}. Shrink. left moves until size <= 2. basket={3:1, 4:1}. max=3.
  • right=5: basket={3:2, 4:1}. max=3.
  • right=6: basket={3:2, 4:1, 5:1}. Shrink. basket={3:1, 5:1}. max=3.
  • right=7: basket={3:1, 5:2}. max=3.
  • right=8: basket={3:1, 5:3}. Window size 4. max=4.

Answer: 4 (window [3, 5, 5, 5]).

How does this generalize to k distinct values?

Replace basket.size() > 2 with basket.size() > k. The rest of the code stays identical.

JAVA
public static int longestWithKDistinct(int[] arr, int k) {
    Map<Integer, Integer> window = new HashMap<>();
    int left = 0, maxLen = 0;
    for (int right = 0; right < arr.length; right++) {
        window.merge(arr[right], 1, Integer::sum);
        while (window.size() > k) {
            int leftVal = arr[left];
            window.merge(leftVal, -1, Integer::sum);
            if (window.get(leftVal) == 0) window.remove(leftVal);
            left++;
        }
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

What is the time and space complexity?

| Aspect | Complexity |
|---|---|
| Time | O(n), each pointer moves forward at most n times |
| Space | O(1) effective, map holds at most k+1 = 3 keys transiently |

What are common mistakes?

Not removing keys when their count reaches zero, causing the map size to be inaccurate.

Forgetting to shrink fully (using if instead of while), which leaves the window with too many distinct types.

What are the edge cases?

  • All trees same type: the entire array is the answer.
  • All trees different types: the answer is 2 (any two adjacent trees).
  • Empty array: return 0.
  • Single tree: return 1.

What should a senior engineer know?

The entire value of this problem is spotting the reduction. Once you see it is k-distinct with k=2, the solution is the standard sliding window template. Demonstrating that you see one unified template behind several differently-worded problems is exactly what interviewers want.

The removal-on-zero rule is the common bug source across all frequency-map sliding window problems.

What are common interview follow-up questions?

  • What if you have k baskets instead of 2? (Parameterize the limit.)
  • What if you want the shortest window with at least k distinct types? (Reverse the shrink condition.)
  • What about the longest substring with at most k distinct characters? (Same algorithm on a character array.)

Visual Overview

TEXT
Trees: [1, 2, 1, 3, 4, 3, 5, 5, 5]   (two baskets)

right=0: basket={1:1}        window=[1]       max=1
right=1: basket={1:1,2:1}    window=[1,2]     max=2
right=2: basket={1:2,2:1}    window=[1,2,1]   max=3
right=3: basket={1:2,2:1,3:1} SIZE 3! Shrink:
         remove 1->1:1, still 3. remove 2->0, delete. left=2.
         basket={1:1,3:1}    window=[1,3]     max=3
right=4: basket has 3 types. Shrink to {3:1,4:1}. max=3.
right=5: basket={3:2,4:1}    window size=3    max=3
right=6: basket has 3 types. Shrink to {3:1,5:1}. max=3.
right=7: basket={3:1,5:2}    window size=3    max=3
right=8: basket={3:1,5:3}    window size=4    max=4

Answer: 4 (window [3,5,5,5])
DIAGRAM
┌──────────────────────────────────────────────┐
│       Fruits Into Baskets Flow                │
├──────────────────────────────────────────────┤
│                                              │
│   left = 0, maxFruits = 0                    │
│   For right = 0 to n-1:                      │
│       │                                      │
│       ▼                                      │
│   basket[trees[right]]++   (expand)          │
│       │                                      │
│       ▼                                      │
│   ┌────────────────────────────┐             │
│   │ While basket.size > 2:     │             │
│   │   basket[trees[left]]--    │ (shrink)    │
│   │   if count == 0: remove    │             │
│   │   left++                   │             │
│   └────────────────────────────┘             │
│       │                                      │
│       ▼                                      │
│   maxFruits = max(maxFruits, right-left+1)   │
└──────────────────────────────────────────────┘

Key Takeaway

Fruits into Baskets sounds like a puzzle about picking fruit, but the entire insight is recognizing that it is the longest-subarray-with-at-most-two-distinct-values problem. Two baskets means at most two distinct types, and once you make that translation, the solution is the familiar variable-size sliding window with a frequency map.

Expand the right pointer, incrementing each type's count. When the map holds more than two distinct types, shrink from the left, decrementing and removing keys when their count reaches zero. Track the maximum window length throughout.

At the National Bank of India, Rajesh reviewed trading desk instrument types and wanted the longest continuous run using at most two instrument types. The sliding window enforced the limit naturally by shrinking the moment a third distinct type appeared.

The senior-level point is that the same template generalizes immediately to any k-distinct problem by parameterizing the limit. The removal-on-zero rule from the frequency map is the common bug source. Demonstrating that you see one unified template behind multiple problem framings is exactly the signal interviewers look for.

Remember one sentence: two baskets means at most two distinct types, so use the k-distinct sliding window with k equals two.

---

Share
Use ← → arrow keys to navigate