2141. Maximum Running Time of N Computers
Problem Description
You have n
computers and an array of batteries. Each battery has a certain capacity - the i-th
battery can power a computer for batteries[i]
minutes.
Your goal is to run all n
computers simultaneously for as long as possible. Here are the rules:
- Initially, you can insert at most one battery into each computer
- At any point in time, you can swap batteries between computers instantly (removing and inserting takes no time)
- Each battery can only power one computer at a time
- Batteries cannot be recharged - once their power is used, it's gone
- You want all
n
computers running at the same time
The problem asks you to find the maximum number of minutes that all n
computers can run simultaneously.
For example, if you have 2 computers and batteries with capacities [3, 3, 3]
minutes, you could:
- Start with 2 batteries in the 2 computers (each with 3 minutes)
- When those are depleted after 3 minutes, swap in the third battery to one computer
- But since you need both computers running simultaneously, the maximum runtime would be 4 minutes total (you can strategically swap batteries to distribute the 9 total minutes across 2 computers)
The key insight is that you can freely swap batteries to optimize the runtime, as long as each computer has a battery at any given moment during the simultaneous operation period.
Intuition
Let's think about what happens when we try to run all n
computers for t
minutes. The key observation is that if we can run all computers for t
minutes, we can definitely run them for any time less than t
minutes. This monotonic property suggests binary search might work.
Now, how do we check if it's possible to run all computers for t
minutes? Consider what happens with each battery:
- If a battery has capacity greater than
t
minutes, we can only uset
minutes from it (since we're only running fort
minutes total) - If a battery has capacity less than or equal to
t
minutes, we can use all of it
Since we can swap batteries freely and instantly, the problem becomes: can we distribute the available battery power to keep n
computers running for t
minutes?
For n
computers running t
minutes each, we need a total of n * t
minutes of battery power. We can get at most min(battery[i], t)
minutes from each battery. So the condition becomes:
sum(min(battery[i], t) for all batteries) >= n * t
This gives us a clear way to check feasibility for any given time t
.
The binary search approach emerges naturally:
- Search space: from
0
tosum(all batteries)
(maximum possible if we had just 1 computer) - For each candidate time
mid
, check if we have enough total usable battery power - If yes, we can potentially run longer, so search the right half
- If no, we need to reduce the time, so search the left half
The beauty of this solution is that it transforms a complex scheduling problem into a simple arithmetic check by recognizing that with free swapping, only the total usable power matters, not the specific assignment of batteries to computers.
Learn more about Greedy, Binary Search and Sorting patterns.
Solution Approach
We implement the solution using binary search on the answer space. Here's how the algorithm works:
Binary Search Setup:
- Initialize left boundary
l = 0
(minimum possible runtime) - Initialize right boundary
r = sum(batteries)
(maximum theoretical runtime if we had only 1 computer)
Binary Search Loop:
While l < r
:
-
Calculate the middle point:
mid = (l + r + 1) >> 1
- The
>> 1
is a bitwise right shift, equivalent to integer division by 2 - We use
(l + r + 1)
instead of(l + r)
to avoid infinite loops whenl
andr
are adjacent
- The
-
Feasibility Check:
- For each battery, calculate how much power we can use if running for
mid
minutes:min(battery[i], mid)
- Sum up all usable battery power:
sum(min(x, mid) for x in batteries)
- Check if total usable power is enough:
>= n * mid
- For each battery, calculate how much power we can use if running for
-
Search Space Adjustment:
- If feasible (we have enough power for
mid
minutes):- Update
l = mid
(try for longer runtime)
- Update
- If not feasible:
- Update
r = mid - 1
(reduce the runtime)
- Update
- If feasible (we have enough power for
Why This Works:
The key insight is that when checking if we can run for mid
minutes:
- Batteries with capacity >
mid
can only contributemid
minutes (capped by runtime) - Batteries with capacity ≤
mid
contribute their full capacity
By summing min(battery[i], mid)
for all batteries, we get the total usable battery minutes. If this sum is at least n * mid
, we have enough power to keep all n
computers running for mid
minutes through strategic battery swapping.
Time Complexity: O(m * log(S))
where m
is the number of batteries and S
is the sum of all battery capacities.
Space Complexity: O(1)
as we only use a few variables for the binary search.
The algorithm converges when l
equals r
, which represents the maximum number of minutes all computers can run simultaneously.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through an example with n = 2
computers and batteries = [3, 3, 3]
.
Step 1: Initialize Binary Search Boundaries
- Left boundary:
l = 0
(minimum runtime) - Right boundary:
r = 3 + 3 + 3 = 9
(total battery capacity)
Step 2: First Iteration
- Calculate middle:
mid = (0 + 9 + 1) / 2 = 5
- Check if we can run for 5 minutes:
- Battery 1:
min(3, 5) = 3
minutes usable - Battery 2:
min(3, 5) = 3
minutes usable - Battery 3:
min(3, 5) = 3
minutes usable - Total usable:
3 + 3 + 3 = 9
minutes - Need for 2 computers:
2 × 5 = 10
minutes - Since
9 < 10
, we cannot run for 5 minutes
- Battery 1:
- Update:
r = 5 - 1 = 4
Step 3: Second Iteration
- Calculate middle:
mid = (0 + 4 + 1) / 2 = 2
- Check if we can run for 2 minutes:
- Each battery:
min(3, 2) = 2
minutes usable - Total usable:
2 + 2 + 2 = 6
minutes - Need for 2 computers:
2 × 2 = 4
minutes - Since
6 ≥ 4
, we can run for 2 minutes
- Each battery:
- Update:
l = 2
Step 4: Third Iteration
- Calculate middle:
mid = (2 + 4 + 1) / 2 = 3
- Check if we can run for 3 minutes:
- Each battery:
min(3, 3) = 3
minutes usable - Total usable:
3 + 3 + 3 = 9
minutes - Need for 2 computers:
2 × 3 = 6
minutes - Since
9 ≥ 6
, we can run for 3 minutes
- Each battery:
- Update:
l = 3
Step 5: Fourth Iteration
- Calculate middle:
mid = (3 + 4 + 1) / 2 = 4
- Check if we can run for 4 minutes:
- Each battery:
min(3, 4) = 3
minutes usable - Total usable:
3 + 3 + 3 = 9
minutes - Need for 2 computers:
2 × 4 = 8
minutes - Since
9 ≥ 8
, we can run for 4 minutes
- Each battery:
- Update:
l = 4
Step 6: Termination
- Now
l = 4
andr = 4
, so the loop ends - The answer is 4 minutes
This makes sense: With 9 total battery minutes and 2 computers, we can theoretically achieve 4.5 minutes per computer, but since we need whole minutes and must keep both running simultaneously, the maximum is 4 minutes.
Solution Implementation
1class Solution:
2 def maxRunTime(self, n: int, batteries: List[int]) -> int:
3 # Binary search on the answer - find maximum runtime where all n computers can run
4 left, right = 0, sum(batteries)
5
6 while left < right:
7 # Calculate middle value (using +1 to avoid infinite loop when left and right are adjacent)
8 # Right shift by 1 is equivalent to dividing by 2
9 mid = (left + right + 1) >> 1
10
11 # Check if we can run n computers for 'mid' minutes
12 # Each battery can contribute at most 'mid' minutes (capped by its capacity)
13 # Total contribution must be at least n * mid for all computers to run 'mid' minutes
14 total_contribution = sum(min(battery_capacity, mid) for battery_capacity in batteries)
15
16 if total_contribution >= n * mid:
17 # If feasible, try to find a larger runtime
18 left = mid
19 else:
20 # If not feasible, reduce the runtime
21 right = mid - 1
22
23 return left
24
1class Solution {
2 public long maxRunTime(int n, int[] batteries) {
3 // Initialize binary search boundaries
4 // left: minimum possible runtime (0 minutes)
5 // right: maximum possible runtime (sum of all battery capacities)
6 long left = 0;
7 long right = 0;
8 for (int battery : batteries) {
9 right += battery;
10 }
11
12 // Binary search to find the maximum runtime
13 while (left < right) {
14 // Calculate mid point (use +1 to avoid infinite loop when left and right are adjacent)
15 long mid = (left + right + 1) >> 1;
16
17 // Calculate total usable battery capacity at runtime 'mid'
18 // Each battery can contribute at most 'mid' minutes
19 long totalUsableCapacity = 0;
20 for (int battery : batteries) {
21 totalUsableCapacity += Math.min(mid, battery);
22 }
23
24 // Check if we can run n computers for 'mid' minutes
25 // We need at least n * mid total battery capacity
26 if (totalUsableCapacity >= n * mid) {
27 // Can sustain this runtime, try for a longer time
28 left = mid;
29 } else {
30 // Cannot sustain this runtime, try for a shorter time
31 right = mid - 1;
32 }
33 }
34
35 // Return the maximum runtime found
36 return left;
37 }
38}
39
1class Solution {
2public:
3 long long maxRunTime(int n, vector<int>& batteries) {
4 // Initialize binary search boundaries
5 // left: minimum possible runtime (0)
6 // right: maximum possible runtime (sum of all battery capacities)
7 long long left = 0, right = 0;
8 for (int battery : batteries) {
9 right += battery;
10 }
11
12 // Binary search for the maximum runtime
13 while (left < right) {
14 // Calculate mid point (using +1 to avoid infinite loop when left and right are adjacent)
15 long long mid = (left + right + 1) >> 1;
16
17 // Calculate total effective capacity at runtime 'mid'
18 // Each battery can contribute at most 'mid' units
19 long long totalCapacity = 0;
20 for (int battery : batteries) {
21 totalCapacity += min(static_cast<long long>(battery), mid);
22 }
23
24 // Check if we can run n computers for 'mid' time units
25 // We need at least n * mid total capacity
26 if (totalCapacity >= n * mid) {
27 // If possible, try to find a larger runtime
28 left = mid;
29 } else {
30 // If not possible, reduce the runtime
31 right = mid - 1;
32 }
33 }
34
35 // Return the maximum possible runtime
36 return left;
37 }
38};
39
1/**
2 * Calculates the maximum runtime for n computers using the given batteries
3 * Uses binary search to find the maximum time all computers can run simultaneously
4 *
5 * @param n - Number of computers to power
6 * @param batteries - Array of battery capacities (in minutes)
7 * @returns Maximum number of minutes all computers can run simultaneously
8 */
9function maxRunTime(n: number, batteries: number[]): number {
10 // Initialize binary search bounds
11 // left: minimum possible runtime (0 minutes)
12 let left = 0n;
13 // right: maximum possible runtime (sum of all battery capacities)
14 let right = 0n;
15
16 // Calculate the total capacity of all batteries
17 for (const batteryCapacity of batteries) {
18 right += BigInt(batteryCapacity);
19 }
20
21 // Binary search for the maximum runtime
22 while (left < right) {
23 // Calculate middle point (using BigInt to handle large numbers)
24 // Adding 1n ensures we round up for proper binary search convergence
25 const mid = (left + right + 1n) >> 1n;
26
27 // Calculate total usable battery capacity at runtime 'mid'
28 // Each battery can contribute at most 'mid' minutes
29 let totalUsableCapacity = 0n;
30 for (const batteryCapacity of batteries) {
31 // A battery can contribute min(its capacity, target runtime)
32 totalUsableCapacity += BigInt(Math.min(batteryCapacity, Number(mid)));
33 }
34
35 // Check if we have enough total capacity to run n computers for 'mid' minutes
36 // Need: n computers * mid minutes = total required capacity
37 if (totalUsableCapacity >= mid * BigInt(n)) {
38 // Can sustain this runtime, try for a longer time
39 left = mid;
40 } else {
41 // Cannot sustain this runtime, try shorter time
42 right = mid - 1n;
43 }
44 }
45
46 // Convert result back to regular number and return
47 return Number(left);
48}
49
Time and Space Complexity
The time complexity is O(m × log S)
, where m
is the number of batteries (length of the batteries list) and S
is the sum of all battery powers.
The binary search runs for O(log S)
iterations since we're searching in the range [0, sum(batteries)]
. In each iteration of the binary search, we compute sum(min(x, mid) for x in batteries)
, which iterates through all m
batteries, taking O(m)
time. Therefore, the overall time complexity is O(m × log S)
.
The space complexity is O(1)
as we only use a constant amount of extra space for variables l
, r
, and mid
. The generator expression sum(min(x, mid) for x in batteries)
doesn't create an intermediate list but computes the sum on-the-fly, using constant extra space.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Overflow in Binary Search Boundary
Pitfall: Setting the right boundary as sum(batteries)
can cause integer overflow in languages with fixed integer sizes when battery capacities are large.
Solution: In Python, this isn't an issue due to arbitrary precision integers, but in languages like Java or C++, use long
type or cap the right boundary at sum(batteries) // n
since that's the theoretical maximum anyway.
2. Incorrect Binary Search Middle Calculation
Pitfall: Using mid = (left + right) // 2
instead of mid = (left + right + 1) // 2
can cause an infinite loop when left = right - 1
and the condition at mid
is satisfied.
Example scenario:
- If
left = 3, right = 4
andmid = 3
satisfies the condition - We set
left = mid = 3
, keeping us in the same state forever
Solution: Always use mid = (left + right + 1) // 2
when updating left = mid
in the binary search to ensure progress.
3. Misunderstanding the Feasibility Check Logic
Pitfall: Thinking that batteries must be assigned to specific computers or that we need to simulate the actual battery swapping process.
Incorrect approach:
# Wrong: Trying to assign batteries to computers
if len(batteries) >= n and all(b >= mid for b in batteries[:n]):
# This doesn't account for battery swapping optimization
Solution: The correct approach uses the greedy insight that we can pool all available battery minutes (capped at mid
) and check if the total is sufficient for n * mid
minutes of runtime.
4. Off-by-One Error in Binary Search
Pitfall: Using while left <= right
with this update pattern can cause the algorithm to miss the correct answer or get stuck.
Solution: Stick to while left < right
with the update pattern of left = mid
and right = mid - 1
to ensure convergence at the correct answer.
5. Not Capping Battery Contribution
Pitfall: Forgetting to use min(battery_capacity, mid)
and instead using the full battery capacity when checking feasibility.
Incorrect:
total_contribution = sum(batteries) # Wrong!
if total_contribution >= n * mid:
...
Solution: Each battery can only contribute up to mid
minutes toward the target runtime, regardless of its actual capacity. A 100-minute battery only provides 10 useful minutes if we're checking for a 10-minute runtime.
Which of the following array represent a max heap?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Don’t Miss This!