1742. Maximum Number of Balls in a Box

EasyHash TableMathCounting
Leetcode Link

Problem Description

In this problem, we are situated in a hypothetical ball factory where balls are numbered sequentially starting from lowLimit up to highLimit. We need to organize these balls into boxes based on a particular rule: the number of the box in which a ball is placed equals the sum of the digits of that ball's number. For example, if we have a ball numbered 321, it goes into box 3 + 2 + 1 = 6, while a ball numbered 10 will be put into box 1 + 0 = 1.

The task is to determine the count of balls in the box that ends up containing the most balls after all the balls numbered from lowLimit to highLimit have been placed according to the aforementioned rule.

Intuition

To find the solution to this problem, we employ a straightforward counting approach. We understand from the problem that the maximum ball number can't exceed 10^5, consequently the sum of the digits of any ball can't be more than 9+9+9+9+9=45 (since 99999 is the largest number less than 10^5 with the most significant digit sum). This observation allows us to safely assume that we do not need to consider box numbers (digit sums) greater than 50.

With this in mind, we can create an array, cnt, to keep track of the number of balls in each box, indexed by the sum of the digits of the ball numbers. This array has a size of 50, as no digit sum will exceed this value. We then iterate over each ball from lowLimit to highLimit, calculate the sum of its digits, and increase the respective count in the cnt array by one for that digit sum.

Finally, the maximum count in the cnt array will tell us the number of balls in the box with the most balls. This constitutes our answer to the problem.

Learn more about Math patterns.

Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

What's the output of running the following function using the following tree as input?

1def serialize(root):
2    res = []
3    def dfs(root):
4        if not root:
5            res.append('x')
6            return
7        res.append(root.val)
8        dfs(root.left)
9        dfs(root.right)
10    dfs(root)
11    return ' '.join(res)
12
1import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4    StringJoiner res = new StringJoiner(" ");
5    serializeDFS(root, res);
6    return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10    if (root == null) {
11        result.add("x");
12        return;
13    }
14    result.add(Integer.toString(root.val));
15    serializeDFS(root.left, result);
16    serializeDFS(root.right, result);
17}
18
1function serialize(root) {
2    let res = [];
3    serialize_dfs(root, res);
4    return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8    if (!root) {
9        res.push("x");
10        return;
11    }
12    res.push(root.val);
13    serialize_dfs(root.left, res);
14    serialize_dfs(root.right, res);
15}
16

Solution Approach

The solution approach is direct and leverages the concept of simulation and counting. The primary steps in the solution involved using a simulation algorithm to model the placement of balls into boxes and employing an elementary data structure (an array) to keep track of this simulation.

Here's a breakdown of how it works:

  1. Create a Counting Array: We initialize an array named cnt of size 50, as determined by the largest possible sum of the digits of the ball numbers. This array will serve as a map from the sum of the digits (which we can consider as the "box number") to the count of balls that go into the respective box.

  2. Iterate Ball Numbers: We iterate over the range from lowLimit to highLimit, inclusive, representing each ball's number.

  3. Sum of Digits Calculation: For each ball number, we calculate the sum of its digits. We do this by repeatedly retrieving the last digit using the modulo operator (x % 10) and then trimming the last digit off by integer division (x //= 10). The sum of these digits represents the box number where the ball will be placed.

  4. Count Balls in Boxes: Corresponding to the sum of digits, we increment the count in the cnt array by one (cnt[y] += 1). This effectively places the ball into the correct box and keeps count of the number of balls in each box.

  5. Identify the Box with the Most Balls: To finalize the solution, we identify the box with the maximum count of balls by taking the maximum value in the cnt array (max(cnt)). This provides us with the required count of balls in the box that has the highest number of balls.

The choice of data structures and algorithms in this solution is based on both the constraints of the problem (such as the range of ball numbers) and the need for a simple yet efficient method to keep a tally of the balls being placed into boxes. The array serves as an easily accessible structure to increment counts, and its fixed size (derived from the constraints) ensures that the solution is space-efficient. The simulation element in the algorithm models the real-world action of placing balls into boxes, giving a methodical approach to achieving the final goal of the problem.

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

What is the space complexity of the following code?

1int sum(int n) {
2  if (n <= 0) {
3    return 0;
4  }
5  return n + sum(n - 1);
6}

Example Walkthrough

Let's walk through a small example to illustrate the solution approach. Suppose we have the following limits for the ball numbers: lowLimit = 5 and highLimit = 15. This means we need to organize ball numbers 5 through 15 into boxes based on the sum of digits rule.

  1. Create a Counting Array: Initiate an array cnt[50] to zero to count the balls in each box.

  2. Iterate Ball Numbers: Start iterating from ball number 5 to 15.

  3. Sum of Digits Calculation: Calculate sum of digits for each ball number.

    • Ball 5: Sum of digits is 5; it goes to box 5.
    • Ball 6: Sum of digits is 6; it goes to box 6.
    • Ball 7: Sum of digits is 7; it goes to box 7.
    • Ball 8: Sum of digits is 8; it goes to box 8.
    • Ball 9: Sum of digits is 9; it goes to box 9.
    • Ball 10: Sum of digits is 1 + 0 = 1; it goes to box 1.
    • Ball 11: Sum of digits is 1 + 1 = 2; it goes to box 2.
    • Ball 12: Sum of digits is 1 + 2 = 3; it goes to box 3.
    • Ball 13: Sum of digits is 1 + 3 = 4; it goes to box 4.
    • Ball 14: Sum of digits is 1 + 4 = 5; it goes to box 5.
    • Ball 15: Sum of digits is 1 + 5 = 6; it goes to box 6.
  4. Count Balls in Boxes: Increment the count in the cnt array for each sum of digits.

    • For ball 5, cnt[5] += 1.
    • For ball 6, cnt[6] += 1.
    • For ball 7, cnt[7] += 1.
    • For ball 8, cnt[8] += 1.
    • For ball 9, cnt[9] += 1.
    • For ball 10, cnt[1] += 1.
    • For ball 11, cnt[2] += 1.
    • For ball 12, cnt[3] += 1.
    • For ball 13, cnt[4] += 1.
    • For ball 14, cnt[5] += 1 (since cnt[5] already has 1, now it is 2).
    • For ball 15, cnt[6] += 1 (since cnt[6] already has 1, now it is 2).
  5. Identify the Box with the Most Balls: Look for the maximum value in the cnt array.

    • After counting, we find that cnt[5] and cnt[6] each have a count of 2, which are the highest counts.

So in this example, the boxes that end up with the most balls are boxes 5 and 6, both containing 2 balls each. This would be the answer returned by the algorithm for our lowLimit and highLimit range of 5 to 15.

Not Sure What to Study? Take the 2-min Quiz:

How many times is a tree node visited in a depth first search?

Python Solution

1class Solution:
2    def countBalls(self, low_limit: int, high_limit: int) -> int:
3        # Initialize a list to keep track of the count of balls in each box.
4        # Assuming the maximum possible sum of the digits is less than 50.
5        count = [0] * 50
6      
7        # Iterate through each number from low_limit to high_limit, inclusive.
8        for num in range(low_limit, high_limit + 1):
9            # Calculate the sum of the digits of the current number.
10            sum_of_digits = 0
11            temp_num = num
12            while temp_num:
13                sum_of_digits += temp_num % 10
14                temp_num //= 10
15          
16            # Increment the count corresponding to the box with the index of the sum.
17            count[sum_of_digits] += 1
18      
19        # Return the count of the most populated box.
20        return max(count)
21

Java Solution

1import java.util.Arrays; // Necessary import for using Arrays.stream()
2
3public class Solution {
4  
5    // This method counts the maximum number of balls with the same sum of digits 
6    // between the given lowLimit and highLimit (inclusive).
7    public int countBalls(int lowLimit, int highLimit) {
8        // Assume the highest possible sum of digits in any ball number is less than 50
9        int[] count = new int[50];
10      
11        // Iterate through each ball number from lowLimit to highLimit
12        for (int i = lowLimit; i <= highLimit; ++i) {
13            int sumOfDigits = 0; // Initialize sum of digits for the current ball number
14
15            // Calculate the sum of digits for the current ball number
16            for (int number = i; number > 0; number /= 10) {
17                sumOfDigits += number % 10; // Add the last digit to the sum
18            }
19
20            // Increment the count for the computed sum of digits
21            ++count[sumOfDigits];
22        }
23      
24        // Find the maximum count in the array and return it
25        // Uses Java 8 Streams to find the max value in the count array
26        return Arrays.stream(count).max().getAsInt();
27    }
28}
29

C++ Solution

1#include <algorithm> // Include algorithm header for the max function
2
3class Solution {
4public:
5    // Function to count the maximum number of balls in a box
6    int countBalls(int lowLimit, int highLimit) {
7        // Initialize the array to hold counts for each possible box number (max sum of digits from 1 to 99999 is 45)
8        int boxCounts[46] = {0}; // Increased to 46 to fit all possible sums of digits
9        int maxBalls = 0; // Variable to store the maximum number of balls in a box
10      
11        // Iterate over the range from lowLimit to highLimit, inclusive
12        for (int i = lowLimit; i <= highLimit; ++i) {
13            int boxNumber = 0; // Variable to store the sum of the digits (box number)
14            // Calculate boxNumber by summing up the digits of `i`
15            for (int x = i; x != 0; x /= 10) {
16                boxNumber += x % 10;
17            }
18            // Increment the ball count for this particular box
19            boxCounts[boxNumber]++;
20            // Update the maxBalls if the count for current box exceeds the previous maximum
21            maxBalls = std::max(maxBalls, boxCounts[boxNumber]);
22        }
23      
24        return maxBalls; // Return the maximum number of balls in any of the boxes
25    }
26};
27

Typescript Solution

1// Function to count the maximum number of balls in a box after distributing them according to their number's sum of digits
2function countBalls(lowLimit: number, highLimit: number): number {
3    // Array to store the count of balls for each possible sum of digits (0-45, so 50 is a safe upper limit)
4    const ballCountArray: number[] = Array(50).fill(0);
5
6    // Loop over each number from lowLimit to highLimit
7    for (let number = lowLimit; number <= highLimit; ++number) {
8        let digitSum = 0; // Variable to hold the sum of digits of the current number
9
10        // Iterate over the digits of the number
11        for (let n = number; n > 0; n = Math.floor(n / 10)) {
12            digitSum += n % 10; // Add the rightmost digit to the sum
13        }
14
15        // Increment the count for the box corresponding to this sum of digits
16        ballCountArray[digitSum]++;
17    }
18
19    // Return the maximum count of balls from the array
20    return Math.max(...ballCountArray);
21}
22
Fast Track Your Learning with Our Quick Skills Quiz:

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30

Time and Space Complexity

Time Complexity

The given code iterates through all the numbers from lowLimit to highLimit inclusive. The time complexity is determined by two factors: the number of iterations and the complexity of the operations within each iteration.

For each number (x) in the range, the inner while loop breaks down the number into its digits to calculate the sum of digits (y). In the worst case, the number of digits for a number x is proportional to the logarithm of x to the base 10, or O(log10(x)). Since the largest possible value of x in our range is highLimit, we can denote this as O(log10(m)), where m = highLimit.

The number of iterations is n, where n = highLimit - lowLimit + 1. Therefore, the total time complexity is O(n * log10(m)) since each iteration's computational overhead is O(log10(m)).

Space Complexity

The space complexity is determined by the additional space used by the algorithm besides the input and output. In this case, the only significant additional storage is the cnt array, whose size is constant at 50. Therefore, the space complexity is O(1), which means it does not scale with the input size n or the value of highLimit.

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


Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫