Minimum Time Required
Category: Search
Difficulty: Medium
Given the number of days it takes each machine to produce an item, determine how many days it will take to fulfill an order of items.
Input: An array \(m[n]\) of machines and a goal \(g\), where the \(i^\text{th}\) machine produces 1 item after every \(m[i]\) days.
Output: the number of days it will take to produce at least \(g\) items.
The first thing to observe is that, after a given number of days, we can compute how many items each machine has produced so far. Machine \(i\) produces an item after each \(m[i]\) days, so after \(d\) days,
We need to search for the day \(d\) where the number of items is no longer less than \(g\):
It is easy to compute items\((d)\) for any \(d\), but it might seem hard to find this point without just trying \(d = 1, 2, 3, \ldots\) until you find it. A good way to do this is with an exponential search, which is similar to a binary search. The idea is to try \(d = 1, 2, 4, 8, \ldots\) until you find some \(2^k\) that has \(\text{items}(2^{k - 1}) < g \leq \text{items}(2^k)\). Then, you do a binary search within the range \([2^{k - 1}, 2^k]\) to find the exact value \(d\). Since \(d\) could be very large, this is usually significantly faster than a linear search.
Java 8:
static long minTime(long[] machines, long goal) {
long target = 1L;
long itemCount = items(machines, target);
while (itemCount < goal) {
target *= 2L;
itemCount = items(machines, target);
}
long lowTarget = target / 2L;
long highTarget = target;
while (lowTarget + 1 < highTarget) {
target = (highTarget + lowTarget) / 2L;
itemCount = items(machines, target);
if (itemCount < goal) {
lowTarget = target;
} else {
highTarget = target;
}
}
return highTarget;
}
private static long items(long[] machines, long days) {
long result = 0L;
for (long machine : machines) {
result += days / machine;
}
return result;
}
C++:
long items(vector<long>, long);
long minTime(vector<long> machines, long goal) {
long target = 1L;
long itemCount = items(machines, target);
while (itemCount < goal) {
target *= 2L;
itemCount = items(machines, target);
}
long lowTarget = target / 2L;
long highTarget = target;
while (lowTarget + 1 < highTarget) {
target = (highTarget + lowTarget) / 2L;
itemCount = items(machines, target);
if (itemCount < goal) {
lowTarget = target;
} else {
highTarget = target;
}
}
return highTarget;
}
long items(vector<long> machines, long days) {
long result = 0L;
for (auto m = machines.begin(); m != machines.end(); m++) {
result += days / *m;
}
return result;
}
Python 3:
def minTime(machines, goal):
def items(days):
return sum(days // m for m in machines)
target = 1
item_count = items(target)
while item_count < goal:
target *= 2
item_count = items(target)
low_target, high_target = target // 2, target
while low_target + 1 < high_target:
target = (high_target + low_target) // 2
item_count = items(target)
if item_count < goal:
low_target = target
else:
high_target = target
return high_target