1742. Maximum Number of Balls in a Box
Problem Description
You work at a ball factory with numbered balls ranging from lowLimit
to highLimit
(inclusive). The total number of balls is n = highLimit - lowLimit + 1
. You also have an infinite supply of boxes numbered from 1 to infinity.
Your task is to place each ball into a specific box based on a simple rule: each ball goes into the box whose number equals the sum of the ball's digits. For instance:
- Ball number
321
goes into box3 + 2 + 1 = 6
- Ball number
10
goes into box1 + 0 = 1
After placing all balls from lowLimit
to highLimit
into their respective boxes according to this digit sum rule, you need to find which box contains the most balls and return that count.
The solution iterates through each ball number from lowLimit
to highLimit
, calculates the sum of its digits, and tracks how many balls end up in each box using an array. Since the maximum ball number is at most 10^5
, the digit sum can never exceed 45
(which would be 99999
), so an array of size 50
is sufficient to track all possible boxes. The algorithm then returns the maximum count found across all boxes.
Intuition
The key insight is recognizing that we need to count how many balls go into each box, then find the maximum count. Since each ball's destination box is determined by its digit sum, we need to calculate the digit sum for every ball number in our range.
To approach this problem, let's first think about the constraints. What's the maximum possible digit sum we could encounter? Given that highLimit
can be at most 10^5
(100,000), the largest digit sum would come from a number like 99,999
, which gives us 9 + 9 + 9 + 9 + 9 = 45
. This tells us we only need to track at most 46 different boxes (digit sums from 1 to 45).
This bounded range of possible digit sums is crucial - it means we can use a simple array to count occurrences rather than a more complex data structure like a hash map. We create an array cnt
where cnt[i]
represents how many balls are in box i
.
The solution becomes straightforward:
- For each ball number from
lowLimit
tohighLimit
, calculate its digit sum - Increment the counter for that digit sum (box number)
- After processing all balls, find the maximum value in our counter array
The digit sum calculation itself is a standard technique: repeatedly take the remainder when dividing by 10 (to get the last digit), add it to our sum, then integer divide by 10 (to remove the last digit). This process continues until the number becomes 0.
By tracking counts in an array and finding the maximum at the end, we efficiently solve the problem in linear time relative to the number of balls.
Learn more about Math patterns.
Solution Approach
The solution uses an array-based counting approach with digit sum calculation. Let's break down the implementation step by step:
1. Initialize the Counter Array
cnt = [0] * 50
We create an array of size 50 to count balls in each box. Since the maximum digit sum is less than 50 (as analyzed earlier), this array is sufficient to track all possible boxes.
2. Process Each Ball
for x in range(lowLimit, highLimit + 1):
We iterate through every ball number from lowLimit
to highLimit
inclusive.
3. Calculate Digit Sum
For each ball number x
, we calculate its digit sum using the standard digit extraction technique:
y = 0 while x: y += x % 10 # Extract the last digit and add to sum x //= 10 # Remove the last digit
x % 10
gives us the last digit of the numberx //= 10
performs integer division to remove the last digit- We repeat until
x
becomes 0, accumulating the sum in variabley
4. Update Box Count
cnt[y] += 1
Once we have the digit sum y
, we increment the counter for box y
, indicating one more ball has been placed in that box.
5. Find Maximum
return max(cnt)
After processing all balls, we return the maximum value in the cnt
array, which represents the box with the most balls.
Time Complexity: O(n * d)
where n = highLimit - lowLimit + 1
is the number of balls and d
is the average number of digits per ball number.
Space Complexity: O(1)
since the counter array has a fixed size of 50 regardless of input size.
The elegance of this solution lies in its simplicity - by recognizing the bounded nature of digit sums, we can use a fixed-size array for counting, making the implementation both efficient and straightforward.
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 a concrete example with lowLimit = 8
and highLimit = 13
.
Step 1: Initialize counter array
cnt = [0, 0, 0, 0, 0, ...] (array of 50 zeros)
Step 2: Process each ball
Ball 8:
- Calculate digit sum: 8 → digit sum = 8
- Place in box 8:
cnt[8] += 1
- Counter state:
cnt[8] = 1
Ball 9:
- Calculate digit sum: 9 → digit sum = 9
- Place in box 9:
cnt[9] += 1
- Counter state:
cnt[9] = 1
Ball 10:
- Calculate digit sum: 1 + 0 = 1
10 % 10 = 0
(add 0 to sum)10 // 10 = 1
1 % 10 = 1
(add 1 to sum)1 // 10 = 0
(stop)
- Place in box 1:
cnt[1] += 1
- Counter state:
cnt[1] = 1
Ball 11:
- Calculate digit sum: 1 + 1 = 2
- Place in box 2:
cnt[2] += 1
- Counter state:
cnt[2] = 1
Ball 12:
- Calculate digit sum: 1 + 2 = 3
- Place in box 3:
cnt[3] += 1
- Counter state:
cnt[3] = 1
Ball 13:
- Calculate digit sum: 1 + 3 = 4
- Place in box 4:
cnt[4] += 1
- Counter state:
cnt[4] = 1
Step 3: Find maximum After processing all balls, our counter array has:
- Box 1: 1 ball (ball 10)
- Box 2: 1 ball (ball 11)
- Box 3: 1 ball (ball 12)
- Box 4: 1 ball (ball 13)
- Box 8: 1 ball (ball 8)
- Box 9: 1 ball (ball 9)
- All other boxes: 0 balls
The maximum count is 1, so we return 1. In this case, all boxes that received balls have exactly 1 ball each.
For a more interesting example where boxes receive multiple balls, consider lowLimit = 19
and highLimit = 28
:
- Balls 19 and 28 both go to box 10 (1+9=10, 2+8=10)
- Balls 20 and 29 would both go to box 2 and box 11 respectively if 29 were included
- This would result in box 10 having 2 balls, making it the maximum
Solution Implementation
1class Solution:
2 def countBalls(self, lowLimit: int, highLimit: int) -> int:
3 # Initialize a counter array to store the count of balls in each box
4 # Maximum possible sum of digits for numbers up to 10^5 is 45 (99999)
5 # So 50 boxes are sufficient
6 box_counts = [0] * 50
7
8 # Iterate through each ball number from lowLimit to highLimit (inclusive)
9 for ball_number in range(lowLimit, highLimit + 1):
10 # Calculate the sum of digits for current ball number
11 digit_sum = 0
12 temp_number = ball_number
13
14 # Extract and sum each digit
15 while temp_number > 0:
16 digit_sum += temp_number % 10 # Get the last digit
17 temp_number //= 10 # Remove the last digit
18
19 # Increment the count for the box corresponding to this digit sum
20 box_counts[digit_sum] += 1
21
22 # Return the maximum count among all boxes
23 return max(box_counts)
24
1class Solution {
2 public int countBalls(int lowLimit, int highLimit) {
3 // Array to store count of balls in each box
4 // Maximum possible sum of digits is 45 (99999 = 9+9+9+9+9 = 45)
5 // So 50 boxes are sufficient
6 int[] boxCounts = new int[50];
7
8 // Iterate through each ball number from lowLimit to highLimit
9 for (int ballNumber = lowLimit; ballNumber <= highLimit; ballNumber++) {
10 // Calculate the sum of digits for current ball number
11 int digitSum = 0;
12 int tempNumber = ballNumber;
13
14 // Extract each digit and add to sum
15 while (tempNumber > 0) {
16 digitSum += tempNumber % 10; // Get last digit
17 tempNumber /= 10; // Remove last digit
18 }
19
20 // Increment count for the box corresponding to this digit sum
21 boxCounts[digitSum]++;
22 }
23
24 // Find and return the maximum count among all boxes
25 return Arrays.stream(boxCounts).max().getAsInt();
26 }
27}
28
1class Solution {
2public:
3 int countBalls(int lowLimit, int highLimit) {
4 // Array to store count of balls in each box
5 // Maximum possible sum is 9*5=45 (for 99999), so 50 is sufficient
6 int boxCount[50] = {0};
7
8 // Variable to track the maximum number of balls in any box
9 int maxBallsInBox = 0;
10
11 // Iterate through each ball number from lowLimit to highLimit
12 for (int ballNumber = lowLimit; ballNumber <= highLimit; ++ballNumber) {
13 // Calculate the sum of digits for current ball number
14 int digitSum = 0;
15 int tempNumber = ballNumber;
16
17 // Extract and sum each digit
18 while (tempNumber > 0) {
19 digitSum += tempNumber % 10; // Add the last digit
20 tempNumber /= 10; // Remove the last digit
21 }
22
23 // Increment the count for the box with index equal to digit sum
24 boxCount[digitSum]++;
25
26 // Update the maximum count if current box has more balls
27 maxBallsInBox = max(maxBallsInBox, boxCount[digitSum]);
28 }
29
30 // Return the maximum number of balls in any single box
31 return maxBallsInBox;
32 }
33};
34
1/**
2 * Counts the maximum number of balls in any box after distributing balls numbered from lowLimit to highLimit.
3 * Each ball is placed in a box where the box number equals the sum of the ball's digits.
4 *
5 * @param lowLimit - The starting ball number (inclusive)
6 * @param highLimit - The ending ball number (inclusive)
7 * @returns The maximum number of balls in any single box
8 */
9function countBalls(lowLimit: number, highLimit: number): number {
10 // Initialize array to store count of balls in each box
11 // Maximum possible sum of digits for numbers up to 99999 is 45 (9+9+9+9+9)
12 const boxCounts: number[] = Array(50).fill(0);
13
14 // Process each ball number from lowLimit to highLimit
15 for (let ballNumber = lowLimit; ballNumber <= highLimit; ballNumber++) {
16 // Calculate the sum of digits for current ball number
17 let digitSum = 0;
18 let tempNumber = ballNumber;
19
20 // Extract and sum each digit
21 while (tempNumber > 0) {
22 digitSum += tempNumber % 10; // Get the last digit
23 tempNumber = Math.floor(tempNumber / 10); // Remove the last digit
24 }
25
26 // Increment the count for the corresponding box
27 boxCounts[digitSum]++;
28 }
29
30 // Return the maximum count among all boxes
31 return Math.max(...boxCounts);
32}
33
Time and Space Complexity
Time Complexity: O(n × log₁₀(m))
, where n = highLimit - lowLimit + 1
represents the number of integers in the range, and m = highLimit
represents the maximum value in the range.
- The outer loop iterates through all integers from
lowLimit
tohighLimit
, which gives usn
iterations. - For each integer
x
in this range, the inner while loop calculates the sum of its digits. The number of digits in an integerx
is⌊log₁₀(x)⌋ + 1
, which isO(log₁₀(x))
. In the worst case, whenx = highLimit = m
, this becomesO(log₁₀(m))
. - Therefore, the total time complexity is
O(n × log₁₀(m))
.
Space Complexity: O(1)
- The algorithm uses a fixed-size array
cnt
of length 50 to store the count of balls in each box. This size is constant regardless of the input values. - The maximum possible sum of digits occurs when all digits are 9. For a 32-bit integer (maximum value around 2×10⁹), the maximum sum would be 9×10 = 90, but the array size of 50 is sufficient for the problem constraints.
- Additional variables
x
andy
use constant space. - Since the space usage doesn't depend on the input size, the space complexity is
O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Modifying the Loop Variable While Calculating Digit Sum
One of the most common mistakes is directly modifying the loop variable when calculating the digit sum:
Incorrect Code:
for ball_number in range(lowLimit, highLimit + 1):
digit_sum = 0
# WRONG: This modifies ball_number directly!
while ball_number > 0:
digit_sum += ball_number % 10
ball_number //= 10 # This destroys the original value
box_counts[digit_sum] += 1 # ball_number is now 0, not the original value
Why it's wrong: After the first iteration, ball_number
becomes 0, and the loop will not work correctly for subsequent iterations. The range loop expects ball_number
to maintain its value through each iteration.
Correct Solution:
for ball_number in range(lowLimit, highLimit + 1):
digit_sum = 0
temp_number = ball_number # Create a copy to work with
while temp_number > 0:
digit_sum += temp_number % 10
temp_number //= 10 # Modify the copy, not the original
box_counts[digit_sum] += 1
2. Incorrect Array Size Assumption
Another pitfall is using an array that's too small or making incorrect assumptions about the maximum digit sum:
Incorrect Code:
# WRONG: Assuming max digit sum is 9 (single digit) box_counts = [0] * 10 # Or WRONG: Using exact calculation but forgetting index starts at 0 box_counts = [0] * 45 # Will fail for digit sum of 45 (index out of bounds)
Correct Solution:
# Use a safely sized array that accounts for: # - Maximum number 99999 has digit sum of 45 # - Array indices start at 0 # - Add some buffer for safety box_counts = [0] * 50 # or even [0] * 46 would work
3. Alternative Correct Approach Using Dictionary
If you're unsure about the array size, using a dictionary eliminates this concern:
from collections import defaultdict
class Solution:
def countBalls(self, lowLimit: int, highLimit: int) -> int:
box_counts = defaultdict(int)
for ball_number in range(lowLimit, highLimit + 1):
digit_sum = 0
temp_number = ball_number
while temp_number > 0:
digit_sum += temp_number % 10
temp_number //= 10
box_counts[digit_sum] += 1
return max(box_counts.values())
This approach automatically handles any digit sum value without worrying about array bounds.
What data structure does Breadth-first search typically uses to store intermediate states?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
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 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
Want a Structured Path to Master System Design Too? Don’t Miss This!