Facebook Pixel

3477. Fruits Into Baskets II

Problem Description

You have two arrays of integers: fruits and baskets, both of length n.

  • fruits[i] represents the quantity of the ith type of fruit
  • baskets[j] represents the capacity of the jth basket

You need to place fruits into baskets following these rules:

  1. Process fruits from left to right (in order from index 0 to n-1)
  2. For each fruit type, find the leftmost available basket that has capacity greater than or equal to that fruit's quantity
  3. Each basket can hold only one type of fruit (once a basket is used, it cannot be used again)
  4. If no suitable basket is found for a fruit type, that fruit remains unplaced

The goal is to return the count of fruit types that remain unplaced after attempting to place all fruits.

For example, if fruits = [4, 2, 5] and baskets = [3, 6, 2]:

  • Fruit type 0 (quantity 4): Check baskets from left - basket 0 has capacity 3 (too small), basket 1 has capacity 6 (≥ 4), so place in basket 1
  • Fruit type 1 (quantity 2): Check baskets from left - basket 0 has capacity 3 (≥ 2), so place in basket 0
  • Fruit type 2 (quantity 5): Check baskets from left - basket 2 has capacity 2 (too small), and baskets 0 and 1 are already used, so this fruit remains unplaced
  • Result: 1 fruit type remains unplaced
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to simulate a greedy allocation process where we try to place each fruit type into the first available basket that can accommodate it. This naturally leads to a straightforward simulation approach.

The key insight is that we need to:

  1. Keep track of which baskets have already been used (since each basket can only hold one fruit type)
  2. For each fruit, scan through all baskets from left to right to find the first suitable one

We can track basket usage with a boolean array vis where vis[i] = True means basket i has been used. Initially, all baskets are unused (False).

For counting unplaced fruits, we can start with the assumption that all n fruits will be unplaced (ans = n), then decrement this count each time we successfully place a fruit. This is simpler than counting failures.

The algorithm naturally follows the problem constraints:

  • We process fruits in order (outer loop through fruits)
  • For each fruit x, we check baskets from left to right (inner loop through baskets)
  • We only use a basket if it's both available (not vis[i]) and has sufficient capacity (y >= x)
  • Once we place a fruit, we mark that basket as used (vis[i] = True) and reduce our unplaced count (ans -= 1)
  • If no suitable basket is found in the inner loop, the fruit remains unplaced and we move to the next fruit

This greedy approach works because we're required to use the leftmost suitable basket - there's no benefit to "saving" a basket for later use.

Learn more about Segment Tree and Binary Search patterns.

Solution Approach

The solution implements a simulation approach using a greedy algorithm to place fruits into baskets.

Data Structures Used:

  • A boolean array vis of size n to track which baskets have been used
  • An integer counter ans initialized to n to track unplaced fruits

Algorithm Steps:

  1. Initialize tracking variables:

    • Create vis = [False] * n where all baskets start as unused
    • Set ans = n assuming initially all fruits are unplaced
  2. Process each fruit in order:

    for x in fruits:

    For each fruit quantity x, we attempt to find a suitable basket.

  3. Find the leftmost suitable basket:

    for i, y in enumerate(baskets):
        if y >= x and not vis[i]:
    • Iterate through baskets from left to right
    • Check two conditions:
      • y >= x: basket capacity y must be at least the fruit quantity x
      • not vis[i]: basket i must not have been used yet
  4. Place the fruit if a suitable basket is found:

    vis[i] = True
    ans -= 1
    break
    • Mark basket i as used
    • Decrement the unplaced fruit count
    • Use break to stop searching once we've placed the fruit (greedy choice)
  5. Return the result: After processing all fruits, ans contains the count of fruits that couldn't be placed in any basket.

Time Complexity: O(n²) where n is the length of the arrays, as we potentially check all baskets for each fruit in the worst case.

Space Complexity: O(n) for the vis array to track basket usage.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's trace through a small example: fruits = [3, 5, 2] and baskets = [4, 2, 5]

Initial Setup:

  • vis = [False, False, False] (all baskets available)
  • ans = 3 (assume all fruits unplaced initially)

Processing Fruit 0 (quantity = 3):

  • Check basket 0: capacity 4 ≥ 3 and not used ✓
  • Place fruit 0 in basket 0
  • Update: vis = [True, False, False], ans = 2

Processing Fruit 1 (quantity = 5):

  • Check basket 0: already used (skip)
  • Check basket 1: capacity 2 < 5 (too small)
  • Check basket 2: capacity 5 ≥ 5 and not used ✓
  • Place fruit 1 in basket 2
  • Update: vis = [True, False, True], ans = 1

Processing Fruit 2 (quantity = 2):

  • Check basket 0: already used (skip)
  • Check basket 1: capacity 2 ≥ 2 and not used ✓
  • Place fruit 2 in basket 1
  • Update: vis = [True, True, True], ans = 0

Result: All fruits were successfully placed, so 0 fruits remain unplaced.

The algorithm correctly simulates the greedy placement strategy, always choosing the leftmost available basket with sufficient capacity for each fruit type.

Solution Implementation

1class Solution:
2    def numOfUnplacedFruits(self, fruits: List[int], baskets: List[int]) -> int:
3        # Get the total number of baskets
4        n = len(baskets)
5      
6        # Track which baskets have been used (initially all unused)
7        is_used = [False] * n
8      
9        # Start with assuming all fruits are unplaced
10        unplaced_count = len(fruits)
11      
12        # Try to place each fruit in a basket
13        for fruit_size in fruits:
14            # Look for the first available basket that can hold this fruit
15            for basket_index, basket_capacity in enumerate(baskets):
16                # Check if basket has enough capacity and hasn't been used yet
17                if basket_capacity >= fruit_size and not is_used[basket_index]:
18                    # Mark this basket as used
19                    is_used[basket_index] = True
20                    # One less unplaced fruit
21                    unplaced_count -= 1
22                    # Move to the next fruit
23                    break
24      
25        # Return the number of fruits that couldn't be placed
26        return unplaced_count
27
1class Solution {
2    /**
3     * Calculates the number of fruits that cannot be placed in baskets.
4     * Each fruit can only be placed in a basket with capacity >= fruit size.
5     * Each basket can hold at most one fruit.
6     * 
7     * @param fruits  Array containing the sizes of fruits
8     * @param baskets Array containing the capacities of baskets
9     * @return The number of fruits that remain unplaced
10     */
11    public int numOfUnplacedFruits(int[] fruits, int[] baskets) {
12        int numberOfFruits = fruits.length;
13        int numberOfBaskets = baskets.length;
14      
15        // Track which baskets have been used
16        boolean[] isBasketUsed = new boolean[numberOfBaskets];
17      
18        // Start with all fruits unplaced
19        int unplacedFruits = numberOfFruits;
20      
21        // Try to place each fruit
22        for (int fruitSize : fruits) {
23            // Find the first available basket that can hold this fruit
24            for (int basketIndex = 0; basketIndex < numberOfBaskets; basketIndex++) {
25                // Check if basket is large enough and not already used
26                if (baskets[basketIndex] >= fruitSize && !isBasketUsed[basketIndex]) {
27                    // Place the fruit in this basket
28                    isBasketUsed[basketIndex] = true;
29                    unplacedFruits--;
30                    break; // Move to the next fruit
31                }
32            }
33        }
34      
35        return unplacedFruits;
36    }
37}
38
1class Solution {
2public:
3    int numOfUnplacedFruits(vector<int>& fruits, vector<int>& baskets) {
4        int n = baskets.size();
5        vector<bool> isBasketUsed(n, false);  // Track which baskets have been used
6        int unplacedCount = fruits.size();    // Initially all fruits are unplaced
7      
8        // Try to place each fruit in a suitable basket
9        for (int fruitSize : fruits) {
10            // Find the first available basket that can hold this fruit
11            for (int i = 0; i < n; ++i) {
12                // Check if basket capacity is sufficient and basket is not already used
13                if (baskets[i] >= fruitSize && !isBasketUsed[i]) {
14                    isBasketUsed[i] = true;    // Mark basket as used
15                    --unplacedCount;            // One less unplaced fruit
16                    break;                      // Move to next fruit
17                }
18            }
19        }
20      
21        return unplacedCount;
22    }
23};
24
1/**
2 * Calculates the number of fruits that cannot be placed in baskets.
3 * Each fruit can only be placed in a basket with capacity >= fruit size.
4 * Each basket can hold at most one fruit.
5 * 
6 * @param fruits - Array of fruit sizes
7 * @param baskets - Array of basket capacities
8 * @returns Number of fruits that remain unplaced
9 */
10function numOfUnplacedFruits(fruits: number[], baskets: number[]): number {
11    const basketCount: number = baskets.length;
12  
13    // Track which baskets have been used
14    const isBasketUsed: boolean[] = Array(basketCount).fill(false);
15  
16    // Start with all fruits unplaced
17    let unplacedCount: number = fruits.length;
18  
19    // Try to place each fruit
20    for (const fruitSize of fruits) {
21        // Find the first available basket that can hold this fruit
22        for (let basketIndex = 0; basketIndex < basketCount; basketIndex++) {
23            if (baskets[basketIndex] >= fruitSize && !isBasketUsed[basketIndex]) {
24                // Place the fruit in this basket
25                isBasketUsed[basketIndex] = true;
26                unplacedCount--;
27                break; // Move to the next fruit
28            }
29        }
30    }
31  
32    return unplacedCount;
33}
34

Time and Space Complexity

The time complexity is O(n × m), where n is the length of the array fruits and m is the length of the array baskets. This is because there is a nested loop structure - the outer loop iterates through all fruits (n iterations), and for each fruit, the inner loop potentially iterates through all baskets (up to m iterations in the worst case). Even though the inner loop may break early, in the worst case scenario where no matches are found or all matches occur at the end of the baskets array, we would need to check all baskets for each fruit.

The space complexity is O(m), where m is the length of the array baskets. This is due to the vis array which has a size equal to the number of baskets. The variable ans and loop variables use constant additional space.

Note: The reference answer appears to be incorrect or referring to a different implementation. The given code has vis = [False] * n where n = len(fruits), but the vis array is actually indexed by basket positions (vis[i] where i comes from enumerate(baskets)), which suggests there might be a bug if the number of baskets differs from the number of fruits. If we assume the code should be vis = [False] * len(baskets), then the space complexity would be O(m) where m is the length of baskets.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Not Breaking After Finding a Suitable Basket

The Pitfall: A common mistake is forgetting to add the break statement after successfully placing a fruit in a basket. Without the break, the loop continues checking remaining baskets and might place the same fruit multiple times.

Incorrect Code:

for fruit_size in fruits:
    for basket_index, basket_capacity in enumerate(baskets):
        if basket_capacity >= fruit_size and not is_used[basket_index]:
            is_used[basket_index] = True
            unplaced_count -= 1
            # Missing break here! Loop continues...

Why It's Wrong:

  • The same fruit could be "placed" in multiple baskets
  • The unplaced_count would be decremented multiple times for a single fruit
  • Multiple baskets would be marked as used for one fruit

The Fix: Always include break after successfully placing a fruit to ensure each fruit is processed exactly once:

for fruit_size in fruits:
    for basket_index, basket_capacity in enumerate(baskets):
        if basket_capacity >= fruit_size and not is_used[basket_index]:
            is_used[basket_index] = True
            unplaced_count -= 1
            break  # Critical: stop looking for more baskets

2. Incorrectly Initializing the Unplaced Count

The Pitfall: Starting with unplaced_count = 0 and trying to increment it when fruits can't be placed, rather than starting with the total and decrementing.

Incorrect Approach:

unplaced_count = 0  # Wrong initialization
for fruit_size in fruits:
    placed = False
    for basket_index, basket_capacity in enumerate(baskets):
        if basket_capacity >= fruit_size and not is_used[basket_index]:
            is_used[basket_index] = True
            placed = True
            break
    if not placed:
        unplaced_count += 1  # Requires extra tracking

Why the Original Approach is Better:

  • Starting with unplaced_count = len(fruits) and decrementing is cleaner
  • Avoids needing an extra placed flag variable
  • More intuitive: we assume all fruits are unplaced initially, then subtract those we successfully place

3. Using the Wrong Basket Selection Strategy

The Pitfall: Trying to optimize by finding the "best fit" basket (smallest basket that can hold the fruit) instead of the leftmost suitable basket.

Incorrect Code:

# Wrong: trying to find the smallest suitable basket
best_basket = -1
min_capacity = float('inf')
for basket_index, basket_capacity in enumerate(baskets):
    if basket_capacity >= fruit_size and not is_used[basket_index]:
        if basket_capacity < min_capacity:
            min_capacity = basket_capacity
            best_basket = basket_index

if best_basket != -1:
    is_used[best_basket] = True
    unplaced_count -= 1

Why It's Wrong: The problem specifically requires using the leftmost available basket, not the best-fit basket. This greedy leftmost approach is part of the problem requirements, not an optimization choice.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More