Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@
* [Petethebaker](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/petethebaker.py)
* Search
* Binary Search
* Maxruntime N Computers
* [Test Max Runtime](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/search/binary_search/maxruntime_n_computers/test_max_runtime.py)
* [Test Binary Search](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/search/binary_search/test_binary_search.py)
* Interpolation
* [Test Interpolation Search](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/search/interpolation/test_interpolation_search.py)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Maximum Running Time of N Computers

You are given an integer, n, representing the number of computers, and a 0-indexed integer array, batteries, where
batteries[i] denotes the number of minutes the ith battery can power a computer.

Your goal is to run all n computers simultaneously for the maximum possible number of minutes using the available
batteries.

Initially, you may assign at most one battery to each computer. After that, at any moment, you may remove a battery
from a computer and replace it with another battery—either an unused battery or one taken from another computer.
This replacement process can be repeated any number of times and takes no time.

Each battery can power any computer multiple times, but only until it is completely drained. Batteries cannot be
recharged.

Return the maximum number of minutes you can run all n computers simultaneously.

Constraints:

- 1 ≤ `n` ≤ `batteries.length` ≤ 10^5
- 1 ≤ `batteries[i]` ≤ 10^5

## Examples

![Example 1](images/examples/max_runtime_n_computers_example_1.png)
![Example 2](images/examples/max_runtime_n_computers_example_2.png)
![Example 3](images/examples/max_runtime_n_computers_example_3.png)

## Solution

This solution aims to find the maximum number of minutes all `n` computers can run simultaneously using a set of batteries.
We use a modified binary search pattern on the possible runtime values to achieve this. The key observation is that if
it’s possible to run all n computers for x minutes, it is also possible to run them for any time less than `x`. This
monotonic property makes binary search applicable. To solve this, we set the search space from 0 to `total_power // n`,
where `total_power` is the sum of all battery capacities. At each step, we check whether running all computers for mid
minutes is feasible by verifying that the sum of the available battery contributions (each battery contributing up to
mid minutes) is at least `n * mid`. This feasibility check helps us efficiently narrow down the maximum achievable runtime.

Now, let’s look at the solution steps below:

1. Set `left=0` and `right=sum(batteries) // n` to define the minimum and maximum possible simultaneous runtime.
2. While `left < right`:
- Calculate `mid = right - (rught - left) // 2` (biases the midpoint toward the higher end to avoid infinite loops).
- Initialize `usable=0` to store the sum of usable power
- For each battery, add `min(b, mid)` to `usable`
- If `usable >= mid * n`, the target feasible, so set `left=mid` to search for a longer time.
- Otherwise, set `right = mid-1` to search in the lower half
3. After the loop completes, `left` holds the maximum number of minutes that all `n` computers can run simultaneously.

![Solution 1](images/solution/max_runtime_n_computers_solution_1.png)
![Solution 2](images/solution/max_runtime_n_computers_solution_2.png)
![Solution 3](images/solution/max_runtime_n_computers_solution_3.png)
![Solution 4](images/solution/max_runtime_n_computers_solution_4.png)
![Solution 5](images/solution/max_runtime_n_computers_solution_5.png)
![Solution 6](images/solution/max_runtime_n_computers_solution_6.png)
![Solution 7](images/solution/max_runtime_n_computers_solution_7.png)
![Solution 8](images/solution/max_runtime_n_computers_solution_8.png)
![Solution 9](images/solution/max_runtime_n_computers_solution_9.png)

### Time Complexity

The time complexity of the solution is `O(n⋅logT)`), where `n` is the number of batteries and `T` is the total power of
one computer, `T = sum(batteries) // n)`. This is because binary search runs in `O(logT)` iterations, and in each
iteration, we compute the usable power by iterating through all `n` batteries, which takes `O(n)` time.

### Space Complexity

The space complexity of the solution os `O(1)` because no extra space is used
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from typing import List


def max_runtime(batteries: List[int], n: int) -> int:
"""
Determines the maximum runtime of n computers given the power available from each battery.

The function uses binary search to find the maximum runtime that can power n computers for the given amount of time.

The function takes a list of integers representing the power available from each battery and an integer representing
the number of computers to power.

The function returns an integer representing the maximum runtime that can power the computers for the given amount of time.

:param batteries: A list of integers representing the power available from each battery.
:param n: An integer representing the number of computers to power.

:return: An integer representing the maximum runtime that can power the computers for the given amount of time.
"""
left = 0
right = sum(batteries) // n
result = 0

while left <= right:
mid = (left + right) // 2

if can_run_for(batteries, n, mid):
left = mid + 1
result = mid
else:
right = mid - 1

return result


def can_run_for(batteries: List[int], n: int, target_time: int) -> bool:
"""
Determines whether the given list of batteries can power n computers for the given amount of time.

:param batteries: A list of integers representing the power available from each battery.
:param n: An integer representing the number of computers to power.
:param target_time: An integer representing the amount of time to power the computers for.

:return: A boolean indicating whether the batteries can power the computers for the given amount of time.
"""
power_needed = n * target_time
power_available = sum(min(battery, target_time) for battery in batteries)
return power_available >= power_needed


def max_run_time_2(batteries: List[int], n: int) -> int:

"""
Finds the maximum runtime that can power the computers for the given amount of time.

:param batteries: A list of integers representing the power available from each battery.
:param n: An integer representing the number of computers to power.

:return: An integer representing the maximum runtime that can power the computers for the given amount of time.
"""

total_power = sum(batteries)
left, right = 0, total_power // n

while left < right:
mid = right - (right - left) // 2
usable = sum(min(b, mid) for b in batteries)

if usable >= mid * n:
left = mid
else:
right = mid - 1
return left
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import unittest
from parameterized import parameterized
from . import max_runtime, max_run_time_2


class MaxRunTimeTestCase(unittest.TestCase):

@parameterized.expand([
([2,3,3,4], 3, 4),
([1,1,4,5], 2, 5),
([2,2,2,2], 1, 8),
([7,2,5,10,8], 2, 16),
([1,2,3,4,5], 2, 7),
([3,4,3,4,5,5,8,2], 4, 8),
([5,2,4], 2, 5),
([1,6,2,6,8], 5, 1)
])
def test_max_runtime_1(self, batteries, n, expected):
actual = max_runtime(batteries, n)
self.assertEqual(expected, actual)

@parameterized.expand([
([2,3,3,4], 3, 4),
([1,1,4,5], 2, 5),
([2,2,2,2], 1, 8),
([7,2,5,10,8], 2, 16),
([1,2,3,4,5], 2, 7),
([3,4,3,4,5,5,8,2], 4, 8),
([5,2,4], 2, 5),
([1,6,2,6,8], 5, 1)
])
def test_max_runtime_2(self, batteries, n, expected):
actual = max_run_time_2(batteries, n)
self.assertEqual(expected, actual)


if __name__ == '__main__':
unittest.main()
Loading