Problem Description
We are given an array of integers (called “balls”) where each integer represents the number on the ball. We must partition (or “assign”) these balls into several boxes subject to two rules:
- All balls within a given box must have the same number (though the same number may appear in different boxes).
- If we look at the sizes (i.e. counts) of balls in all boxes, the difference between the largest and smallest box count must be at most one.
Return the fewest number of boxes (groups) we need to assign all the balls following these rules.
Key Insights
- The boxes must be “nearly balanced” – every box’s size is either m or m+1 for some integer m.
- We are allowed to split the balls of the same number across boxes.
- For each ball type with frequency f, if we decide to use t boxes for that number then the t boxes will each receive either m or m+1 balls; hence, the total count f must lie between tm and t(m+1).
- Globally if we use k boxes, then there exist an integer m and an “extra‐box count” r such that: • n = m*k + r (where n is the total number of balls, and 0 ≤ r < k) • All boxes have size m or m+1.
- For each distinct ball number with frequency f, if we “split” its f balls into t boxes then t must lie between: • Lower bound: ceil(f/(m+1)) (if every box for that type gets the larger quantity) • Upper bound: floor(f/m) (if every box for that type gets the smaller quantity)
- In addition, when summing over all ball types, the total number of boxes used (i.e. the sum across the types of the t values) must equal k. Also, the “extra” balls summed over the ball types must add up to r.
- A neat approach is to “guess” the smaller box size L (which plays the role of m). Notice that L must be at most the minimum frequency among the ball types (otherwise a ball type with less than L balls cannot fill even a single box of size L).
- For a chosen L the total number of boxes k must satisfy two conditions: • Based on the overall total n, since boxes are of size L or L+1, we have: ceil(n/(L+1)) ≤ k ≤ floor(n/L). • For each ball type with frequency f, if we must use between ceil(f/(L+1)) and floor(f/L) boxes then overall: sum(ceil(f/(L+1))) ≤ k ≤ sum(f // L).
- We then try each candidate L (from 1 to the minimum frequency) and, if the two ranges intersect, choose the smallest possible k from the intersection.
- This greedy “range‐intersection” approach finds the minimal number of boxes needed.
Space and Time Complexity
Time Complexity: O(D) where D is the number of distinct ball numbers (D ≤ length of the input, up to 10^5).
Space Complexity: O(D) for storing the frequency counts.
Solution
We solve the problem by iterating over possible candidate values for the smaller box size L (which must lie between 1 and the minimum frequency among the ball types). For a given L, the total number of boxes k must satisfy two sets of constraints:
-
From the total number of balls n: • k must be at least ceil(n/(L+1)) and at most floor(n/L).
-
From the distribution over each ball type: • For a ball type with frequency f, using t boxes to store its f balls needs to satisfy: ceil(f/(L+1)) ≤ t ≤ floor(f/L) • Therefore, when summing over all ball types, k must lie between: total_lower = sum(ceil(f/(L+1))) and total_upper = sum(f // L)
If there is an intersection between the range [ceil(n/(L+1)), floor(n/L)] and [total_lower, total_upper] then a valid assignment with k boxes is possible. Among all candidate L with a nonempty intersection, we pick the smallest k available.
We then implement this logic and provide commented solutions in Python, JavaScript, C++ and Java.