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
ncomputers 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
tminutes, we can only usetminutes from it (since we're only running fortminutes total) - If a battery has capacity less than or equal to
tminutes, 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
0tosum(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 Implementation
1class Solution:
2 def maxRunTime(self, n: int, batteries: List[int]) -> int:
3 """
4 Find the maximum time all n computers can run simultaneously.
5
6 Uses binary search with the boundary-finding template to find
7 the maximum feasible runtime.
8
9 Args:
10 n: Number of computers to power
11 batteries: List of battery capacities in minutes
12
13 Returns:
14 Maximum number of minutes all computers can run simultaneously
15 """
16
17 def feasible(target_time: int) -> bool:
18 """
19 Check if all n computers can run for target_time minutes.
20
21 Each battery can contribute at most target_time minutes.
22 Total contribution must be at least n * target_time.
23
24 Args:
25 target_time: The target runtime to check
26
27 Returns:
28 True if target_time is achievable, False otherwise
29 """
30 total_contribution = sum(min(battery, target_time) for battery in batteries)
31 return total_contribution >= n * target_time
32
33 # Binary search for the maximum feasible runtime
34 left, right = 0, sum(batteries)
35 first_true_index = -1
36
37 while left <= right:
38 mid = (left + right) // 2
39
40 if feasible(mid):
41 first_true_index = mid
42 left = mid + 1 # Try for longer runtime
43 else:
44 right = mid - 1 # Reduce runtime
45
46 return first_true_index
471class Solution {
2 private int n;
3 private int[] batteries;
4
5 /**
6 * Find the maximum time all n computers can run simultaneously.
7 *
8 * Uses binary search with boundary-finding template.
9 *
10 * @param n Number of computers to power
11 * @param batteries Array of battery capacities in minutes
12 * @return Maximum number of minutes all computers can run simultaneously
13 */
14 public long maxRunTime(int n, int[] batteries) {
15 this.n = n;
16 this.batteries = batteries;
17
18 // Calculate total battery capacity for upper bound
19 long left = 0;
20 long right = 0;
21 for (int battery : batteries) {
22 right += battery;
23 }
24
25 long firstTrueIndex = -1;
26
27 // Binary search using the boundary-finding template
28 while (left <= right) {
29 long mid = left + (right - left) / 2;
30
31 if (feasible(mid)) {
32 firstTrueIndex = mid;
33 left = mid + 1; // Try for longer runtime
34 } else {
35 right = mid - 1; // Reduce runtime
36 }
37 }
38
39 return firstTrueIndex;
40 }
41
42 /**
43 * Check if all n computers can run for targetTime minutes.
44 *
45 * @param targetTime The target runtime to check
46 * @return true if targetTime is achievable, false otherwise
47 */
48 private boolean feasible(long targetTime) {
49 long totalContribution = 0;
50 for (int battery : batteries) {
51 totalContribution += Math.min(battery, targetTime);
52 }
53 return totalContribution >= n * targetTime;
54 }
55}
561class Solution {
2public:
3 long long maxRunTime(int n, vector<int>& batteries) {
4 // Lambda function to check if target runtime is feasible
5 auto feasible = [&](long long targetTime) {
6 long long totalContribution = 0;
7 for (int battery : batteries) {
8 totalContribution += min(static_cast<long long>(battery), targetTime);
9 }
10 return totalContribution >= static_cast<long long>(n) * targetTime;
11 };
12
13 // Binary search bounds
14 long long left = 0;
15 long long right = 0;
16 for (int battery : batteries) {
17 right += battery;
18 }
19
20 long long firstTrueIndex = -1;
21
22 // Binary search using the boundary-finding template
23 while (left <= right) {
24 long long mid = left + (right - left) / 2;
25
26 if (feasible(mid)) {
27 firstTrueIndex = mid;
28 left = mid + 1; // Try for longer runtime
29 } else {
30 right = mid - 1; // Reduce runtime
31 }
32 }
33
34 return firstTrueIndex;
35 }
36};
371/**
2 * Calculates the maximum runtime for n computers using the given batteries
3 * Uses binary search with the boundary-finding template
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 /**
11 * Check if all n computers can run for targetTime minutes
12 * @param targetTime - The target runtime to check
13 * @returns true if targetTime is achievable, false otherwise
14 */
15 const feasible = (targetTime: bigint): boolean => {
16 let totalContribution = 0n;
17 for (const battery of batteries) {
18 const contribution = BigInt(battery) < targetTime ? BigInt(battery) : targetTime;
19 totalContribution += contribution;
20 }
21 return totalContribution >= targetTime * BigInt(n);
22 };
23
24 // Calculate total battery capacity for upper bound
25 let left = 0n;
26 let right = 0n;
27 for (const battery of batteries) {
28 right += BigInt(battery);
29 }
30
31 let firstTrueIndex = -1n;
32
33 // Binary search using the boundary-finding template
34 while (left <= right) {
35 const mid = (left + right) / 2n;
36
37 if (feasible(mid)) {
38 firstTrueIndex = mid;
39 left = mid + 1n; // Try for longer runtime
40 } else {
41 right = mid - 1n; // Reduce runtime
42 }
43 }
44
45 return Number(firstTrueIndex);
46}
47Solution Approach
We implement the solution using the binary search boundary-finding template on the answer space.
The Feasible Function:
For a given target runtime t, we check if it's achievable:
def feasible(target_time):
total_contribution = sum(min(battery, target_time) for battery in batteries)
return total_contribution >= n * target_time
Each battery can contribute at most target_time minutes (capped by its capacity). If the total contribution is at least n * target_time, we have enough power to run all computers for target_time minutes.
Binary Search Setup:
- Initialize
left = 0andright = sum(batteries)(maximum theoretical runtime) - Initialize
first_true_index = -1to track the last feasible time found
Binary Search with Template Pattern:
left, right = 0, sum(batteries)
first_true_index = -1
while left <= right:
mid = (left + right) // 2
if feasible(mid):
first_true_index = mid
left = mid + 1 # Try for longer runtime
else:
right = mid - 1 # Reduce runtime
return first_true_index
The search pattern is:
false, false, ..., true, true, true(lower times are feasible, higher times are not)- Wait, actually it's inverted: lower times are always feasible, we want the maximum feasible time
- So we search for the last true (highest feasible runtime)
When feasible(mid) is true:
- Record
first_true_index = mid(this could be our answer) - Try for a longer time:
left = mid + 1
When feasible(mid) is false:
- The time is too long, try shorter:
right = mid - 1
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.
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 an example with n = 2 computers and batteries = [3, 3, 3].
Step 1: Initialize Binary Search Boundaries
- Left boundary:
left = 0(minimum runtime) - Right boundary:
right = 3 + 3 + 3 = 9(total battery capacity) first_true_index = -1
Step 2: First Iteration
- Calculate middle:
mid = (0 + 9) / 2 = 4 - Check if we can run for 4 minutes:
- Battery 1:
min(3, 4) = 3minutes usable - Battery 2:
min(3, 4) = 3minutes usable - Battery 3:
min(3, 4) = 3minutes usable - Total usable:
3 + 3 + 3 = 9minutes - Need for 2 computers:
2 × 4 = 8minutes - Since
9 >= 8, feasible! →first_true_index = 4,left = 5
- Battery 1:
Step 3: Second Iteration
- Calculate middle:
mid = (5 + 9) / 2 = 7 - Check if we can run for 7 minutes:
- Each battery:
min(3, 7) = 3minutes usable - Total usable:
3 + 3 + 3 = 9minutes - Need for 2 computers:
2 × 7 = 14minutes - Since
9 < 14, NOT feasible →right = 6
- Each battery:
Step 4: Third Iteration
- Calculate middle:
mid = (5 + 6) / 2 = 5 - Check if we can run for 5 minutes:
- Each battery:
min(3, 5) = 3minutes usable - Total usable:
9minutes - Need for 2 computers:
2 × 5 = 10minutes - Since
9 < 10, NOT feasible →right = 4
- Each battery:
Step 5: Termination
- Now
left = 5 > right = 4, so the loop ends - The answer is
first_true_index = 4minutes
This makes sense: With 9 total battery minutes and 2 computers, the maximum is 4 minutes (using 8 of the 9 available minutes).
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 left, right, mid, and first_true_index. 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. Using Wrong Binary Search Template Variant
Pitfall: Using while left < right with left = mid pattern, which can cause infinite loops and doesn't match the boundary-finding template.
Example of incorrect approach:
while left < right: mid = (left + right + 1) >> 1 if feasible(mid): left = mid else: right = mid - 1 return left
Solution: Use the standard boundary-finding template with while left <= right and first_true_index tracking:
first_true_index = -1 while left <= right: mid = (left + right) // 2 if feasible(mid): first_true_index = mid left = mid + 1 else: right = mid - 1 return first_true_index
2. 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 for boundaries and calculations:
long right = 0; for (int battery : batteries) { right += battery; }
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. 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:
total_contribution = sum(min(battery, mid) for battery in batteries)
5. Edge Case: first_true_index Never Updated
Pitfall: If no runtime is feasible (which shouldn't happen since 0 is always feasible), returning -1 could cause issues.
Solution: Initialize first_true_index = 0 since running for 0 minutes is always possible, or handle the edge case explicitly:
if not batteries: return 0
You are given an array of intervals where intervals[i] = [start_i, end_i] represent the start and end of the ith interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
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
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
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!