Facebook Pixel

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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 use t minutes from it (since we're only running for t 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 to sum(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
47
1class 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}
56
1class 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};
37
1/**
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}
47

Solution 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 = 0 and right = sum(batteries) (maximum theoretical runtime)
  • Initialize first_true_index = -1 to 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 Evaluator

Example 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) = 3 minutes usable
    • Battery 2: min(3, 4) = 3 minutes usable
    • Battery 3: min(3, 4) = 3 minutes usable
    • Total usable: 3 + 3 + 3 = 9 minutes
    • Need for 2 computers: 2 × 4 = 8 minutes
    • Since 9 >= 8, feasible! → first_true_index = 4, left = 5

Step 3: Second Iteration

  • Calculate middle: mid = (5 + 9) / 2 = 7
  • Check if we can run for 7 minutes:
    • Each battery: min(3, 7) = 3 minutes usable
    • Total usable: 3 + 3 + 3 = 9 minutes
    • Need for 2 computers: 2 × 7 = 14 minutes
    • Since 9 < 14, NOT feasible → right = 6

Step 4: Third Iteration

  • Calculate middle: mid = (5 + 6) / 2 = 5
  • Check if we can run for 5 minutes:
    • Each battery: min(3, 5) = 3 minutes usable
    • Total usable: 9 minutes
    • Need for 2 computers: 2 × 5 = 10 minutes
    • Since 9 < 10, NOT feasible → right = 4

Step 5: Termination

  • Now left = 5 > right = 4, so the loop ends
  • The answer is first_true_index = 4 minutes

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
Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More