1760. Minimum Limit of Balls in a Bag
Problem Description
You have an array nums where nums[i] represents the number of balls in the i-th bag. You can perform up to maxOperations operations to split bags.
In each operation, you can:
- Choose any bag with balls and divide it into two new bags
- Each new bag must contain a positive number of balls
- For example, a bag with 5 balls can be split into bags of 1 and 4 balls, or 2 and 3 balls
Your penalty is defined as the maximum number of balls in any single bag after all operations. The goal is to minimize this penalty.
The problem asks you to find the minimum possible penalty (the smallest possible maximum bag size) that can be achieved using at most maxOperations splits.
For instance, if you have bags [9] and maxOperations = 2, you could:
- Split the bag of 9 into 6 and 3
- Split the bag of 6 into 3 and 3
- Result: bags of [3, 3, 3], giving a penalty of 3
The solution uses binary search to find the minimum penalty. It searches for the smallest maximum bag size that can be achieved within the operation limit. For each candidate maximum size mx, it calculates how many splits are needed: for a bag with x balls to have at most mx balls per bag, you need (x - 1) // mx splits. If the total splits needed is within maxOperations, that maximum size is achievable.
Intuition
The key insight is recognizing that this is an optimization problem where we want to find the minimum possible maximum value. When we think about the relationship between the penalty (maximum bag size) and the number of operations needed, we notice an important pattern: as we allow larger maximum bag sizes, fewer operations are required.
Consider a bag with 9 balls. If we want the maximum to be 3, we need to split it into pieces of at most 3 balls each, requiring 2 operations. But if we allow the maximum to be 5, we only need 1 operation (splitting into 5 and 4). This inverse relationship suggests binary search could work.
The challenge becomes: given a target maximum bag size, how many operations do we need? For a bag with x balls to be split into bags of at most mx balls each, we need ceil(x/mx) - 1 operations. This can be written as (x - 1) // mx operations. We sum this across all bags to get the total operations needed.
Since there's a monotonic relationship (smaller maximum requires more operations, larger maximum requires fewer operations), we can binary search on the answer. We search for the smallest maximum bag size where the required operations don't exceed maxOperations.
The search space is from 1 (minimum possible bag size) to max(nums) (no operations needed). For each candidate maximum in our binary search, we check if it's achievable within the operation limit. The smallest achievable maximum is our answer.
Learn more about Binary Search patterns.
Solution Implementation
1class Solution:
2 def minimumSize(self, nums: List[int], maxOperations: int) -> int:
3 def feasible(max_size: int) -> bool:
4 """
5 Check if we can make all bags have size <= max_size
6 with at most maxOperations splits.
7
8 For each bag of size x, we need (x - 1) // max_size operations
9 to split it into bags of size <= max_size.
10 """
11 total_operations_needed = 0
12 for bag_size in nums:
13 total_operations_needed += (bag_size - 1) // max_size
14 return total_operations_needed <= maxOperations
15
16 # Binary search for the minimum possible maximum bag size
17 left, right = 1, max(nums)
18 first_true_index = -1
19
20 while left <= right:
21 mid = (left + right) // 2
22 if feasible(mid):
23 first_true_index = mid
24 right = mid - 1
25 else:
26 left = mid + 1
27
28 return first_true_index
291class Solution {
2 public int minimumSize(int[] nums, int maxOperations) {
3 int left = 1;
4 int right = Arrays.stream(nums).max().getAsInt();
5 int firstTrueIndex = -1;
6
7 while (left <= right) {
8 int mid = left + (right - left) / 2;
9 if (feasible(nums, mid, maxOperations)) {
10 firstTrueIndex = mid;
11 right = mid - 1;
12 } else {
13 left = mid + 1;
14 }
15 }
16
17 return firstTrueIndex;
18 }
19
20 private boolean feasible(int[] nums, int maxSize, int maxOperations) {
21 long totalOperations = 0;
22 for (int num : nums) {
23 totalOperations += (num - 1) / maxSize;
24 }
25 return totalOperations <= maxOperations;
26 }
27}
281class Solution {
2public:
3 int minimumSize(vector<int>& nums, int maxOperations) {
4 int left = 1;
5 int right = ranges::max(nums);
6 int firstTrueIndex = -1;
7
8 while (left <= right) {
9 int mid = left + (right - left) / 2;
10 if (feasible(nums, mid, maxOperations)) {
11 firstTrueIndex = mid;
12 right = mid - 1;
13 } else {
14 left = mid + 1;
15 }
16 }
17
18 return firstTrueIndex;
19 }
20
21private:
22 bool feasible(vector<int>& nums, int maxSize, int maxOperations) {
23 long long totalOperations = 0;
24 for (int num : nums) {
25 totalOperations += (num - 1) / maxSize;
26 }
27 return totalOperations <= maxOperations;
28 }
29};
301function minimumSize(nums: number[], maxOperations: number): number {
2 const feasible = (maxSize: number): boolean => {
3 let totalOperations = 0;
4 for (const num of nums) {
5 totalOperations += Math.floor((num - 1) / maxSize);
6 }
7 return totalOperations <= maxOperations;
8 };
9
10 let left = 1;
11 let right = Math.max(...nums);
12 let firstTrueIndex = -1;
13
14 while (left <= right) {
15 const mid = Math.floor((left + right) / 2);
16 if (feasible(mid)) {
17 firstTrueIndex = mid;
18 right = mid - 1;
19 } else {
20 left = mid + 1;
21 }
22 }
23
24 return firstTrueIndex;
25}
26Solution Approach
The solution implements a binary search to find the minimum possible maximum bag size. This is a classic "find first true" binary search pattern.
Binary Search Setup:
- Left boundary
left = 1: The minimum possible bag size is 1 ball - Right boundary
right = max(nums): If we don't perform any operations, the maximum is the largest original bag first_true_index = -1: Tracks the minimum achievable maximum bag size
Feasibility Check can_achieve_max_size(max_size):
This function determines if we can achieve a maximum bag size of max_size within maxOperations:
- For each bag with
xballs, we calculate how many splits are needed:(x - 1) // max_size - This formula works because to split
xballs into bags of at mostmax_sizeballs, we needceil(x/max_size) - 1operations - Sum all required operations and check if the total is ≤
maxOperations - Returns
Trueif achievable (feasible),Falseotherwise
Binary Search Template: The algorithm follows the standard "find first true" template:
left, right = 1, max(nums)
first_true_index = -1
while left <= right:
mid = (left + right) // 2
if can_achieve_max_size(mid):
first_true_index = mid
right = mid - 1 # Try to find smaller valid size
else:
left = mid + 1 # Need larger size
return first_true_index
The key characteristics of this template:
- Uses
while left <= right(notleft < right) - When feasible, records
first_true_index = midand searches left withright = mid - 1 - When not feasible, searches right with
left = mid + 1 - Returns
first_true_indexwhich holds the smallest valid maximum size
Time Complexity: O(n * log(max(nums))) where n is the length of the array. We perform binary search over the range [1, max(nums)], and for each iteration, we check all n bags.
Space Complexity: O(1) as we only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [7, 17] and maxOperations = 2.
Step 1: Initialize Binary Search
left = 1(minimum possible bag size)right = max([7, 17]) = 17(maximum without any operations)first_true_index = -1(tracks the answer)
Step 2: Binary Search Process with Template
Iteration 1: left=1, right=17, mid=9
- Check
feasible(9):- Bag with 7 balls:
(7-1)//9 = 0operations - Bag with 17 balls:
(17-1)//9 = 1operation - Total:
0 + 1 = 1 ≤ 2→feasible(9) = True
- Bag with 7 balls:
- Since feasible:
first_true_index = 9,right = 9 - 1 = 8
Iteration 2: left=1, right=8, mid=4
- Check
feasible(4):- Bag with 7 balls:
(7-1)//4 = 1operation - Bag with 17 balls:
(17-1)//4 = 4operations - Total:
1 + 4 = 5 > 2→feasible(4) = False
- Bag with 7 balls:
- Since not feasible:
left = 4 + 1 = 5
Iteration 3: left=5, right=8, mid=6
- Check
feasible(6):- Bag with 7 balls:
(7-1)//6 = 1operation - Bag with 17 balls:
(17-1)//6 = 2operations - Total:
1 + 2 = 3 > 2→feasible(6) = False
- Bag with 7 balls:
- Since not feasible:
left = 6 + 1 = 7
Iteration 4: left=7, right=8, mid=7
- Check
feasible(7):- Bag with 7 balls:
(7-1)//7 = 0operations - Bag with 17 balls:
(17-1)//7 = 2operations - Total:
0 + 2 = 2 ≤ 2→feasible(7) = True
- Bag with 7 balls:
- Since feasible:
first_true_index = 7,right = 7 - 1 = 6
Iteration 5: left=7, right=6
left > right, loop terminates
Result: Return first_true_index = 7
The minimum possible penalty is 7. We split the 17-ball bag twice to get [7, 7, 3], combined with the original 7-ball bag gives us [7, 7, 7, 3]. The maximum is 7.
Time and Space Complexity
The time complexity is O(n × log M), where n is the length of the array nums and M is the maximum value in the array nums.
This complexity arises from:
- Binary search over the range
[1, max(nums)], which hasMelements, takingO(log M)iterations - For each binary search iteration, the
checkfunction is called, which iterates through allnelements innumsto computesum((x - 1) // mx for x in nums), takingO(n)time - Total:
O(n) × O(log M) = O(n × log M)
The space complexity is O(1).
The algorithm only uses a constant amount of extra space for variables in the check function and the binary search operation. The range object in Python is a lazy iterator that doesn't create the entire list in memory, so it doesn't contribute to space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Using Wrong Binary Search Template Variant
Pitfall: Using while left < right with right = mid instead of the correct template:
# WRONG template variant while left < right: mid = (left + right) // 2 if feasible(mid): right = mid else: left = mid + 1 return left
Correct template:
left, right = 1, max(nums)
first_true_index = -1
while left <= right:
mid = (left + right) // 2
if feasible(mid):
first_true_index = mid
right = mid - 1
else:
left = mid + 1
return first_true_index
Key differences:
- Uses
while left <= right(notleft < right) - Tracks the answer in
first_true_index - Uses
right = mid - 1when feasible (notright = mid)
2. Incorrect Split Calculation Formula
Pitfall: Using the wrong formula to calculate the number of operations needed:
x // mx(forgetting to subtract 1)(x + mx - 1) // mx(this gives the number of resulting bags, not operations)x // mx - 1(off by one when x is divisible by mx)
Why the formula (x - 1) // mx works:
- To split x balls into bags of at most mx balls each, you need
ceil(x/mx)total bags - Since you start with 1 bag, you need
ceil(x/mx) - 1operations - The formula
(x - 1) // mxis equivalent toceil(x/mx) - 1
Example:
- With 9 balls and max size 3:
(9-1)//3 = 8//3 = 2operations needed - This creates 3 bags of 3 balls each (9 → 6+3 → 3+3+3)
3. Binary Search Boundary Issues
Pitfall: Setting incorrect search boundaries:
- Starting with
left = 0instead ofleft = 1(bag size must be positive) - Not initializing
first_true_index = -1to handle edge cases
Correct initialization:
left, right = 1, max(nums)
first_true_index = -1
4. Integer Overflow in Other Languages
Pitfall: When translating to languages like C++ or Java, the sum of operations might overflow for large inputs.
Solution: Use appropriate data types:
long long totalOperations = 0; // Use long long instead of int for (int num : nums) { totalOperations += (num - 1) / maxSize; }
5. Misunderstanding the Feasible Function
Pitfall: The feasible function should return True when the condition is satisfied (we CAN achieve the target with given operations), creating a pattern like:
false, false, false, true, true, true, ...
The binary search finds the first true (minimum feasible max size).
Which of the following shows the order of node visit in a Breadth-first Search?

Recommended Readings
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Want a Structured Path to Master System Design Too? Don’t Miss This!