diff --git a/DIRECTORY.md b/DIRECTORY.md index bef1f660..c41219e7 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -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) diff --git a/algorithms/search/binary_search/maxruntime_n_computers/README.md b/algorithms/search/binary_search/maxruntime_n_computers/README.md new file mode 100644 index 00000000..ffab7587 --- /dev/null +++ b/algorithms/search/binary_search/maxruntime_n_computers/README.md @@ -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 diff --git a/algorithms/search/binary_search/maxruntime_n_computers/__init__.py b/algorithms/search/binary_search/maxruntime_n_computers/__init__.py new file mode 100644 index 00000000..4ec45cd5 --- /dev/null +++ b/algorithms/search/binary_search/maxruntime_n_computers/__init__.py @@ -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 diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_1.png b/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_1.png new file mode 100644 index 00000000..44f9e263 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_1.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_2.png b/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_2.png new file mode 100644 index 00000000..7e354c27 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_2.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_3.png b/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_3.png new file mode 100644 index 00000000..1873c868 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/examples/max_runtime_n_computers_example_3.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_1.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_1.png new file mode 100644 index 00000000..22c87660 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_1.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_2.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_2.png new file mode 100644 index 00000000..7d2d5f94 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_2.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_3.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_3.png new file mode 100644 index 00000000..61452314 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_3.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_4.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_4.png new file mode 100644 index 00000000..c053bbe2 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_4.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_5.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_5.png new file mode 100644 index 00000000..6d0e7990 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_5.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_6.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_6.png new file mode 100644 index 00000000..e569e4e7 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_6.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_7.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_7.png new file mode 100644 index 00000000..aae782e1 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_7.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_8.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_8.png new file mode 100644 index 00000000..e4123eb3 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_8.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_9.png b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_9.png new file mode 100644 index 00000000..625490a6 Binary files /dev/null and b/algorithms/search/binary_search/maxruntime_n_computers/images/solution/max_runtime_n_computers_solution_9.png differ diff --git a/algorithms/search/binary_search/maxruntime_n_computers/test_max_runtime.py b/algorithms/search/binary_search/maxruntime_n_computers/test_max_runtime.py new file mode 100644 index 00000000..cd38e1ca --- /dev/null +++ b/algorithms/search/binary_search/maxruntime_n_computers/test_max_runtime.py @@ -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()