Start learning free

LESSON 252 OF 347 · BINARY SEARCH

The Factory in C#: Brute Force Over the Time

Practice O(n * k * T) Read the full explanation

There are N workers in a factory. Each worker packs the same type of product, and for each of them we know the time it takes them to pack one product.

Find out the minimum amount of time the workers need to pack at least K products.

Example:

Input: times = [4, 7, 3, 6, 7, 1], K = 60
Output:30
Explanation:
1st worker packs 7 products in 4 * 7 = 28 units of time
2nd worker packs 4 products in 7 * 4 = 28 units of time
3rd worker packs 10 products in 3 * 10 = 30 units of time
4th worker packs 5 products in 6 * 5 = 30 units of time
5th worker packs 4 products in 7 * 4 = 28 units of time
6th worker packs 30 products in 1 * 30 = 30 units of time
We have 7 + 4 + 10 + 5 + 4 + 30 = 60 total products
in max(28, 28, 30, 30, 28, 30) = 30 units of time
and this is the minimum amount of time
since in 29 units of time we can pack only
7 + 4 + 9 + 4 + 4 + 29 = 57 products

Note:

Your algorithm should run in O(n * k * T) time and use O(1) extra space.


STEP 1 OF 9
    Ctrl + Enter to check

    C# · BINARY SEARCH

    The Factory in C#, explained

    Problem overview

    MinTime receives an int[] times, where times[i] is how many time units worker i needs to pack one product, and an int K. All the workers pack at the same moment, each at their own pace. The method returns the smallest number of time units after which the workers together have packed at least K products.

    In the example, times = {4, 7, 3, 6, 7, 1} and K = 60. After 30 units the workers pack 7, 4, 10, 5, 4 and 30 products, which add up to exactly 60. After 29 units they pack only 7 + 4 + 9 + 4 + 4 + 29 = 57, so 30 is the answer.

    A worker who needs t units per product packs time / t whole products in time units, rounding down. Half a product doesn't count.

    Approach: try the times in increasing order

    The total number of products never decreases as the time grows, because more time can't make anyone pack fewer products. So the first time at which the total reaches K is the answer, and the simplest way to find it is to try 0, 1, 2, ... and stop at the first success.

    Counting the products for one candidate time takes one pass over the workers. If the answer is T, the loop makes about T passes of n workers each. This is slow when the answer is large, and the next lesson on this problem replaces the one-by-one search with a binary search on the time. This lesson stays with the straightforward version.

    Trace the example up to 29. The count at time 29 is 57, which is below 60, so the loop moves on to 30. At 30 the count is 60, the condition count < K becomes false, and the loop ends with time = 30.

    The same observation explains why the loop can stop at the first success. Once the count reaches K at some time, every later time also reaches it, so no later time can be a smaller answer, and no earlier time was good enough or the loop would have stopped there. Without this property, finding the first good time would need a different argument.

    Step by step

    1. Declare time as an int starting at 0. It is the candidate being tested.
    2. Loop while CountProducts(times, time) < K. The helper, written below, returns how many products everyone packs in time units. While that count is too low, the candidate is too small.
    3. Add one unit with time++ inside the loop.
    4. Return time after the loop. The loop stops at the first time where the count reaches K.
    5. Declare the helper above MinTime as public int CountProducts(int[] times, int time).
    6. Start products at 0.
    7. Loop over the workers with foreach (int t in times).
    8. Add time / t to products. Dividing two ints already discards the fractional part, which is the "whole products only" rule.
    9. Return products.

    The solution in C#

    class Solution {
        public int CountProducts(int[] times, int time) {
            int products = 0;
            foreach (int t in times) {
                products += time / t;
            }
            return products;
        }
    
        public int MinTime(int[] times, int K) {
            int time = 0;
            while (CountProducts(times, time) < K) {
                time++;
            }
            return time;
        }
    }
    

    C# details worth knowing

    • Integer division truncates. With two int operands, 29 / 7 is 4, not 4.14. That is exactly the rule for whole products, so no Math.Floor is needed. Casting to double first would give a fraction and break the count.
    • foreach. foreach (int t in times) visits each element in order. It is the natural choice when you don't need the index.
    • Parameter named time. In CountProducts, time is the candidate, and in MinTime it is the local variable that holds it. They are separate variables that happen to share a name.
    • Zero worker time. A worker with t = 0 would make time / t throw a DivideByZeroException. The problem implies that every worker needs a positive time.

    Complexity

    Each call to CountProducts takes O(n) time, where n is the number of workers. The loop calls it once per candidate time, so if the answer is T, the total is about O(n * T). In the worst case T grows with K, because even the fastest worker needs minTime * K units alone, so the time can grow with K.

    The extra space is O(1): a few int variables.

    Edge cases and common mistakes

    • The starting value. At time 0 nobody has packed anything, so 0 is a safe place to start. If K is 0, the count is never below it and the method returns 0 without looping.
    • Returning time - 1 or time + 1. The loop leaves time on the first time that works, so return it as is.
    • Using <= in the loop condition. That would continue past the first time with exactly K products, and return one unit too many.
    • Floating-point division. Computing time / (double)t and adding the results counts fractions of products. Keep the division on integers.
    • Large inputs. This version steps one unit at a time. If the answer is in the millions, it needs millions of passes over the workers. Binary search on the time fixes that.

    Testing

    timesKresult
    {4, 7, 3, 6, 7, 1}6030
    {5}15
    {3, 3}13
    Keep going with C#About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free